快、稳、省、小

  • 流程的操作体验
  • 稳定
  • 省电、省流量
  • 安装包小

不好的体验

  • 卡顿
  • 内存泄露、崩溃
  • 代码质量和逻辑差导致耗流量、耗电
  • 安装包过大

快 怎么才能快?

影响卡顿的因素?

  • 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