框架选型
链接:
UI集:
UI介绍:
https://zhuanlan.zhihu.com/p/68671278
https://zhuanlan.zhihu.com/p/49726145
https://zhuanlan.zhihu.com/p/25324711
网络框架
优点 | 缺点 | |
---|---|---|
HttpClient | 1. 支持连接池、多线程 2. 从官方demo可以看出httpclient只创建一次,被多个线程复用 3. HttpClient4.3后超时配置到request级 |
1. Android已经去掉了HttpClient改用了OKHttp。 2. 使用起来需要自己封装 3. 需要手动关闭httpclient.close() |
OKHttp | 1. 性能方面与httpclient类似 2. 不需要手动关闭 3. Android4.4开始换成OKHttp |
1. 使用时需要自己封装 2. new OkHttpClient()每次使用都需要new出来 3. 超时配置在client级,没到每个request |
Retrofit | 1. 基于OKHttp的封装 2. 基于接口编程。封装度高,基于注解。无需手动关闭 3. Jetpack使用的Retrofit |
1. 与OKHttp类似,new Retrofit.Builder()每次使用都要new 出来 |
路由框架
ARouter | ActivityRouter | VMRouter | SPI | |
---|---|---|---|---|
相关文章 | 开源最佳实践:Android平台页面路由框架ARouter 如何一步步实现一个类似ARouter的Android路由框架 |
Android Router从0到1 | ||
地址 | https://github.com/alibaba/Arouter | https://github.com/mzule/ActivityRouter | https://github.com/meituan/WMRouter | |
共性 | 1. 支持降级处理。 2. 支持Activity的startActivityForResult 3. 组件单独运行的方式:切换library/application方式编译,框架本身没有提供切换方式,开发者自行解决 4. 没有组件调用的超时设置 5. 无法取消组件调用 6. 无法动态注册/注销组件 7. 组件调用代码侵入性都很高 |
1. 支持降级处理。 2. 支持Activity的startActivityForResult 3. 组件单独运行的方式:切换library/application方式编译,框架本身没有提供切换方式,开发者自行解决 4. 没有组件调用的超时设置 5. 无法取消组件调用 6. 无法动态注册/注销组件 7. 组件调用代码侵入性都很高 |
||
通信机制 | 路由+接口下沉 | 路由+静态方法 | ||
activity变量自动注入 | 1. 通过apt生成解析参数的代码 2. 在onCreate方法中调用 ARouter.getInstance().inject(this); 实现自动注入 |
无 | ||
调用方式(页面跳转) | ARouter.getInstance().build("/test/activity").navigation(); |
Router.create(url).open(context); |
||
调用方式(调用服务) | ARouter.getInstance().navigation(HelloService.class).sayHello(); |
与页面跳转相同 | ||
组件向外提供服务 | 接口继承IProvider并下沉到base中,组件中实现接口并通过注解来暴露服务 | 在静态方法上加注解来暴露服务,但不支持返回值,且参数固定位(context, bundle) | ||
Fragment组件化支持 | 调用服务的方式实现,未支持后续Fragment内部的功能调用 | 不支持 | ||
组件自动注册方案 | 新版本(1.3.0)开始支持通过插件完成路由注册 1. apt生成各module的路由表 2. TransformAPI+ASM扫描路由表并注册到LogisticsCenter中,无需手动维护组件列表 |
1. apt生成各module的路由表 2. apt在application的module通过Modules注解生成RouterInit进行注册 3. 需要手动维护Modules注解中的组件列表 |
||
跨app组件调用支持 | 不支持 | 支持 | ||
组件app运行时调用其他组件 | 一起打包或者通过urlScheme来统一转发 | UrlScheme原生支持跨app调用,组件同时安装在设备上接口 通过中介Activity转发:RouterActivity |
||
组件依赖隔离 | 未隔离 | 无需依赖、完全隔离 | ||
AOP支持 | 拦截器AOP | 无 | ||
特点 | 1. 阿里出品,使用者众多,QQ群里交流比较活跃 2. 支持分级按需加载 3. 是一个路由框架,并不是完整的组件化方案,可作为组件化架构通信引擎 |
1. 业内最早的组件化支持库 2. 通过注解静态方法的方式暴露服务 |
||
组件定义代码侵入性 | 注解定义路由及参数自动注入,侵入性高 | 注解定义路由,侵入性高 | ||
混淆配置 | 框架中的所有类及框架相关接口的实现类 | 框架中的所有类 | ||
Easy of use | ||||
starts | 13.1k | 2.8k | 2k | |
大厂使用 | WMRouter:美团外卖Android开源路由框架 | |||
图片加载
Picasso | Glide | Fresco | |
---|---|---|---|
说明 | |||
地址 | https://github.com/square/picasso | https://github.com/bumptech/glide | https://github.com/facebook/fresco |
发布时间 | 2013年5月 | 2014年9月 | 2015年5月 |
是否支持gif | false | true | true |
是否支持webP | true | true | true |
视频缩略图 | false | true | true |
加载速度 | 中 | 高 | 高 |
大小 | 100kb | 500kb | 2~3M |
占内存大小 | |||
Easy of use | low | medium | difficult |
Disk+MenCache | true | true | true |
大厂使用 |
详细属性对比
对比项 | Picasso | Glide | Fresco |
---|---|---|---|
配置 | compile ‘com.github.bumptech.glide:glide:XXX.XXX’ | compile ‘com.facebook.fresco:fresco:XXX.XXX | |
初始化 | 直接使用 | Fresco.initialize(this); | |
layout | 普通ImageView | 独有的SimpleDraweeView | |
圆角, 圆形 | 需要自己实现圆角,继承自BitmapTransformation操作bitmap对象实现 | 通过RoundingParams设置参数 | |
缓存 | Glide内存和磁盘缓存 | 三级缓存,分别是 Bitmap缓存,未解码图片缓存, 文件缓存。 | |
缓存图像大小 | Glide则会根据ImageView控件尺寸获得对应的大小的bitmap来展示,从而缓存也可以针对不同的对象:原始图像(source),结果图像(result) | 缓存原始图像 | |
加载策略 | Glide只有占位图 | 先加载小尺寸图片,再加载大尺寸的 | |
加载进度 | false | true |
Glide和Fresco比较
依赖
Glide:compile com.github.bumptech.glide:glide:3.7.0
Fresco:
1 | compile 'com.facebook.fresco:fresco:1.2.0' |
bitmap操作
Glide:
1 | Bitmap myBitmap = Glide.with(上下文) |
Fresco:
Fresco获取bitmap更加复杂,使用起来也不是那么顺畅。
首先,Fresco为了更好地管理bitmap 对象(bitmap对象申请和释放会引起频繁的GC操作,从而引起界面卡顿), 引入了可关闭的引用(CloseableReference), 持有者在离开作用域的时候需要关闭该引用,而我们要获取的bitmap 对象就是可关闭的引用。也就是说,我们不能像上面Glide那样把bitmap 对象取出来传递给其它地方使用, 只能在Fresco提供的作用域范围内使用。 实际项目中会获取缓冲的文件对象:
1 | //同样在DataSubscriber中获取 |
优点
Glide:
- 多种图片格式的缓存,适用于更多内容表现形式(如 Gif、WebP、缩略图、Video)
- 生命周期集成(根据Activity或Fragment的生命周期管理图片加载请求)
- 高校处理Bitmap(bitmap的复用和主动回收,减少系统回收压力)
- 高校的缓存策略,灵活(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),加载速度快且内存开销小(默认Bitmap格式的不同,使得内存开销是Picasso的一半)
Fresco:
最大的优势在于5.0以下(最低2.3)的bitmap加载。在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem区)
大大减少OOM(在更底层的Native蹭对OOM进行处理,图片将不再占用App的内存)
适用于需要高性能加载大量图片的场景
缺点
Glide:
- 没有文件缓存
- java heap比Fresco高
Fresco:
- 包较大(2~3M)
- 用法复杂
- 底层涉及c++领域,阅读源码深入学习难度大
结论
picasso不支持gif且上面表格体现的数据也不理想,我们忽略它。
专业的图片App用Fresco比较好。普通App用Glide上手快,使用简单,配置方便。
图片裁剪
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
是否会自动矫正角度 | |
大厂使用 | |
图片压缩
Luban | Compress | |
---|---|---|
说明 | 可控制压缩档次。 仿微信朋友圈压缩策略 |
满足几MB图的高保真压缩到几十KB |
地址 | https://github.com/Curzibn/Luban | https://github.com/zetbaitsu/Compressor |
Easy of use | 支持普通调用方式和RxJava调用 | 支持普通调用方式和RxJava调用 |
最后更新时间0 | 3年前 | 2021.3 |
stars | 12.5k | 5.8k |
群友推荐使用 |
开源的。商业使用,记得遵循其对应的开源协议。
Luban的效果与对比
内容 | 原图 | Luban |
Wechat |
---|---|---|---|
截屏 720P | 720*1280,390k | 720*1280,87k | 720*1280,56k |
截屏 1080P | 1080*1920,2.21M | 1080*1920,104k | 1080*1920,112k |
拍照 13M(4:3) | 3096*4128,3.12M | 1548*2064,141k | 1548*2064,147k |
拍照 9.6M(16:9) | 4128*2322,4.64M | 1032*581,97k | 1032*581,74k |
滚动截屏 | 1080*6433,1.56M | 1080*6433,351k | 1080*6433,482k |
Luban
导入Luban
1 | implementation 'top.zibin:Luban:1.1.8' |
使用Luban
方法列表
方法 | 描述 |
---|---|
load | 传入原图 |
filter | 设置开启压缩条件 |
ignoreBy | 不压缩的阈值,单位为K |
setFocusAlpha | 设置是否保留透明通道 |
setTargetDir | 缓存压缩图片路径 |
setCompressListener | 压缩回调接口 |
setRenameListener | 压缩前重命名接口 |
异步调用
Luban内部采用IO线程进行图片压缩,外部调用只需设置好结果监听即可
1 | //普通调用方式 |
同步调用
同步方法请尽量避免在主线程调用以免阻塞主线程,下面以rxJava调用为例
1 | Flowable.just(photos) |
1 | //RxJava方式 |
Compress
导入Compress
1 | dependencies { |
使用Compress
1 | // Compress Image File |
1 | // Stay cool compress image asynchronously with RxJava |
文件上传
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
文件下载
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
视频框架
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
IM
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
弹窗Dialog
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
弹窗PopupWindow
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
上拉加载下拉刷新
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
列表适配器
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
日期选择器
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
滚轮选择器WheelView
说明 | |
地址 | |
加载速度 | |
大小 | |
占内存大小 | |
Easy of use | |
大厂使用 | |
数据存储
SQLite | SharedPreference | GreenDao | Room | Litepal | MMKV | |
---|---|---|---|---|---|---|
说明 | 轻量级关系型 | 腾讯开发。键值对存储(对标SP) | ||||
地址 | https://github.com/greenrobot/greenDAO | https://github.com/guolindev/LitePal | https://github.com/Tencent/MMKV | |||
支持的数据类型 | boolean、int、long、float、double、string、set集合、byte[]、可序列化对象 | |||||
易用性 | ||||||
GreenDao使用
Room使用
Litepal使用
MMKV使用
引入依赖
1
2
3dependencies {
implementation 'com.tencent:mmkv-static:1.2.7'
}在自定义 Application 中初始化
在Application中初始化MMKV的时候,可以采用默认存储路径的方式初始化,也可以采用自定义文件存储路径的方式初始化
1
2
3
4
5
6
7
8
9
10//在App启动时进行MMKV初始化。返回默认储存路径("/data/user/0/项目包名/files/mmkv")
String rootDir = MMKV.initialize(this);
//或者初始化MMKV的时候自定义根目录
//String dir = getFilesDir().getAbsolutePath() + "/mmkv_2";
//String rootDir = MMKV.initialize(dir);
//或者初始化MMKV时自定义某个文件的目录
//String relativePath = getFilesDir().getAbsolutePath() + "/mmkv_3";
//MMKV kv = MMKV.mmkvWithID("testCustomDir", relativePath);MMKV提供一个全局的实例,可以直接使用
1
2
3
4
5
6
7
8import com.tencent.mmkv.MMKV;
MMKV kv = MMKV.defaultMMKV();
kv.encode("bool", true);//存储
boolean bValue = kv.decodeBool("bool");//取出
kv.encode("int", Integer.MIN_VALUE);
int iValue = kv.decodeInt("int");
kv.encode("string", "Hello from mmkv");
String str = kv.decodeString("string");
扫码
- zxing
- 华为统一扫码服务:https://juejin.cn/post/6967890062423883783