最近一个星期居然没有产品的需求,本来打算涂几个妹子过双 11,突然想到许多新人进项目组后会把项目以前踩的坑给再次踩一边,特别是一些会引发性能问题的 “有坏味道” 的代码,虽然一点有问题的代码暂时不管也不会有多大的影响,但是 “千里之堤,毁于蚁穴”,一旦问题严重了就不好处理了。不能指望每次都做好完整的 Code Review,最好的做法是把“性能优化” 的技术点总结一下,输出一个文档,给那些新加入的小伙伴们看看,免得重复踩坑。
其实性能调优涉及到多方面的工作,一晚上也只能想到这么多,而且都是一些老生常谈、炒冷饭的东西,这个贴的目的在于想骗一些高质量的干货(我从未见过如此厚颜无耻之人 + 脑补诸葛孔明表情图),然后我再整合进来,接下来再把每一点都讲详细一点,配合项目中遇到的实例案例进行分析,最好再写个 DEMO 之类的放到 Github 骗骗粉之类的。
请大家补充要点啊,我一并处理。以下只是一时想到写的笔记,详细的分析还需要一点时间。
要点
使用异步
保持 APP 的高度响应,不要在 UI 线程做耗时操作,多使用异步任务
使用线程时要做好线程控制;使用队列、线程池
谨慎使用糟糕的 AysncTask、Timer
警惕异步任务引起的内存泄露
应该异步任务分类,比如 HTTP,图片下载,文件读写,每一类的异步任务维护一个任务队列,而不是每一个任务都开一个线程(Volley 表示我一个可以搞定这些全部 (:з」∠))
这些常用的任务应该做好优先级处理(一般 JSON 数据优先于图片等静态数据的请求)
一般异步任务应该开启一个 SingleAsyncTask,保证一时只有一个线程在工作
HTTP 和图片下载尽量使用同一套网络请求
使用 MVP 模式规范大型 Activity 类的行为,避免异步任务造成的内存泄露
避免内存泄露
了解虚拟机内存回收机制
频繁 GC 也会造成卡顿,避免不必要的内存开销
错误的引用姿势造成的内存泄露(啊~ 要泄了~)
常见的 Activity 泄露(单例、Application、后台线程、无限动画、静态引用)
Bitmap 泄露(HoneyComb 这个问题之前压力好大)
尽量使用 IntentService 代替 Service,前者会自动 StopItself
排查内存泄露问题的方法(我一直以来都是简单暴力的人肉 dump 检查大法)
使用 LeakCanary 自动检查 Activity 泄露问题
对内存负载要保持敏感(Sharp)
视图优化
布局优化、减少层次,Include Merge
使用 ViewStub 避免不必要的 LayoutInflate,使用 GONE 代替重复 LayoutInflate 同一个布局
避免过度绘制,应该减少不必要的布局背景;布局层次太深会造成过度绘制以及 Measure、Layout 等方法时间复杂度的指数增长
使用过渡动画,比如给图片的呈现加一个轻量的淡入效果会让视觉上变得流畅许多
避免过度的动画,不要让一个界面同时出现多出动画,比如 List 滚动时 Item 项要停止播放动画或者 GIF
复杂动画使用 SurfaceView 或 TextureView
尽量提供多套分辨率的图片,使用矢量图
Adapter 优化
复用 convertView,用 ViewHolder 代替频繁 findViewById
不要重复 setListener,要使用 v.getId 来复用 Listener,不然会创建一堆 Listener 导致频繁 GC
多布局要采用 MultiItemView,而不是使用一个大布局然后动态控制需要现实的部分
不要在 getView 方法做做耗时的操作
快速滚动列表的时候,可以停止加载列表项的图片,停止列表项的动画,不要在这时候改变列表项的布局
尽量用 RecyclerView(增量 Notify 和 RecycledViewPool 带你飞)
代码优化
算法优化,减少时间复杂度,参考一些经典的优化算法
尽量使用 int,而不是 float 或者 double
尽量采用基本类型,避免无必要的自动装箱和拆箱,浪费时间和空间
选用合适的集合类(尽量以空间换时间)、选用 Android 家的 SparseArray,SparseBooleanArray 和 LongSparseArray
避免创建额外的对象(StringBuilder)
使用 SO 库完成一些比较独立的功能(高斯模糊)
预处理(提前操作)一些比较耗时的初始化工作统一放到启动图处理
懒加载(延迟处理)规避 Activity 的敏感生命周期
Log 工具类,要在编译时删掉调试代码,而不是在运行时通过判断条件规避
优先使用静态方法、公有方法还是私有方法?速度区别很大哦
类内部直接对成员变量进行操作,不要使用 getter/setter 方法,调用方法耗额外的时间
给内部类访问的外部类成员变量要声明称包内可访问,而不是私有,不然编译的时候还是会自动创建用于访问外部类成员变量的方法
遍历集合时,使用 i++ 代替 Iterator,后者需要额外的对象操作,应在循环体内避免这种情况
如果一个基本类型或者 String 的值不会改变,尽量用 final static,编译时会直接用变量的值替换变量,也就不需要在查询变量的值了
其他优化
数据库优化:使用索引、使用异步线程
网络优化 …… 一堆优秀的轮子
避免过度使用依赖注入框架,大量的反射
不过过度设计 / 抽象,多态看起来很有设计感,代价就是额外的代码、空间、时间
尽量不要开启多进程,进程的开销很大
APK 瘦身
开启混淆
使用 zipalign 工具优化 APK
适当有损图片压缩、使用矢量图
删除项目中冗余的资源,之前写过一些删除没有 res 资源的脚本
动态加载模块化,项目拆分啊!
性能问题的排查方法
GPU 条形图,没事开来看看淘宝
过度绘制颜色,嗯,不要一片姨妈红就好
LeakCanary,自动检测 Activity 泄露,挺好用的
TraceView(Device Monitor),Systrace,分析哪些代码占用的 CPU 时间太大,屡试不爽
Lint,检查不合理的 res 资源
layoutopt(还是 optlayout?),对当前布局提出优化建议,已被 lint 替代,但是还能用
HierarchyViewer,查看手机当前界面的布局层次,布局优化时常用(只用于模拟器,真机上用要 ROOT,不想 ROOT 加得使用 ViewServer)
StrictMode,UI 操作、网络操作等容易出现性能问题的地方,如果出现异常情况 StrictMode 会报警
共同学习,写下你的评论
评论加载中...
作者其他优质文章