快、稳、省、小
- 流程的操作体验
- 稳定
- 省电、省流量
- 安装包小
不好的体验
- 卡顿
- 内存泄露、崩溃
- 代码质量和逻辑差导致耗流量、耗电
- 安装包过大
快 怎么才能快?
影响卡顿的因素?
- UI的刷新、绘制
- 启动,冷启动、热启动、温启动
- 跳转、页面跳转、前后台切换
- 即时反馈、点击事件、滑动事件、系统事件等等
UI
UI绘制原理
- Android 显示过程可以简单概括为:Android 应用程序把经过测量,布局、绘制后的 surface 缓存数据,通过 SurfaceFlinger 把数据渲染到显示屏幕上, 通过 Android 的刷新机制来刷新数据。也就是说应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕上。
- 换一种方式说:Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需的 60FPS。(注:FPS 表示每秒传递的帧数。)在理想情况下,60 FPS 就感觉不到卡,这意味着每个绘制时长应该在16 ms 左右。如果某个操作花费的时间是 24ms ,系统在得到 VSYNC 信号时就无法正常进行正常渲染,这样就发生了丢帧现象。也就是延迟了,这种现象在执行动画或滑动列表比较常见,还有可能是你的 Layout 太过复杂,层叠太多的绘制单元,无法在 16ms 完成渲染,最终引起刷新不及时.
布局优化
- 合理使用背景颜色
- 减少不必要的嵌套层
- 推荐使用Google的新布局:ConstraintLayout
绘制优化
- onDraw中不要创建新的布局对象
- onDraw方法中不要做耗时的任务
- 刷新,尽量减少不必要的刷新、减少刷新面积
启动优化
冷启动是指安装 apk 后首次启动应用程序,或者应用程序上次结束,进程被杀死后重新打开app
- Application的创建过程中,尽量较少耗时操作,比如之前onCreat方法中,做了太多事情,比如地图、友盟、Bugly、等SDK init的操作,那我们现在可以先把网络层初始化,把SDK的加载操作放在onResume方法中。
- 生命周期方法中减少耗时操作
稳
主线程优化
- 内存优化、避免内存泄漏
那些地方会引起内存泄露?
- 集合类泄露,集合list.add()之后,如果不用了尽量list.clear()之后再list = null
- 单例、静态变量 单例引起的内存泄漏,通常是由于引用的context是生命周期短造成的,也就是说生命周期长的持有了生命周期短的引用,造成了内存泄漏。比如Toast,我们传入的是MainActivity,但MainActivity没有用了,需要被销毁,但我们的Tost依然持有其引用导致无法回收,这就导致了内存泄漏。匿名内部类或非静态内部类导致的内存泄漏,这个我们可以采用合理使用JAVA的引用机制来解决,参考Android-强,软,弱,虚引用
- 匿名内部类、非静态内部类
资源未关闭造成的内存泄露
- 网络、文件等流忘记关闭
- 手动注册广播的时候,退出的时候忘记unregisterReceiver()
- Service执行完毕后,忘记stopSelf()
- EventBus等观察者模式的框架忘记手动解除注册
- Bitmap使用完毕,忘记及时Recycle()
小
哪些文件影响包大小?
- assets文件夹,不会生成ID,使用AssetManager类接口获取
- res 会生成ID并映射到R文件,访问的时候直接通过资源ID来
- META-INF 保存应用的签名信息,签名信息可以验证APK的完整性
- AndroidMainfest.xml 这个文件用来描述Android应用的配置信息,一些组件的注册信息,可使用权限等等
- classes.dex Dalvik 字节码程序,让 Dalvik 虚拟机可执行,一般情况下,Android 应用在打包时通过 Android SDK 中的 dx 工具将 Java 字节码转换为 Dalvik 字节码
- resources.arsc 记录着资源文件和资源ID之间的映射关系,用来根据资源ID寻找资源
减少APK包大小的方式
- 使用Studio自带的扫描分析工具lint删除无用资源
- 开启混淆,设置 shrinkResources true和 minifyEnabled true
- 借助第三方工具如 :乐固加固,360压缩
- 不要重复使用库
- 插件化,比如功能模块放在服务器上,按需下载
省
- 省电 谷歌推荐使用 JobScheduler,来调整任务优先级等策略来达到降低损耗的目的。JobScheduler 可以避免频繁的唤醒硬件模块,造成不必要的电量消耗。避免在不合适的时间(例如低电量情况下、弱网络或者移动网络情况下的)执行过多的任务消耗电量
- 省内存 图片压缩
- 图片尺寸压缩、图片质量压缩 Glide就是采用了 Lrucache 和 LruDiskCache 推荐使用
- 省 CPU 资源 线程的使用,这里我推荐使用线程池 https://www.jianshu.com/p/07eb2f7db0ee
- 序列化采用推荐的 Parcelable 代替 Serializable
- 集合如果是插入和删除用的多,建议使用 LinkList。如果修改用的多,建议 ArrayList
- 对常量使用 static final,适用于基本类型和 String 常量
- 使用增强的 for 循环语法(foreach)
- 避免使用浮点数,浮点数比 Android 设备上的整数慢约2倍
- 尽可能少用 wrap_content,wrap_content 会增加布局 measure 时计算成本
- 删除控件中无用的属性
- 合理使用动画,某些情况下可以用硬件加速方式来提供流畅度,或者采用自定义view代替动画,最后记得在Activity的ondestory()方法中调用Animation.cancle()进行动画停止
- 考虑 StringBuilder 代替 String
- 数据量比较大或者内存比较宽裕考虑 HashMap,其他建议使用 SpareArray