Android流畅度优化

Android流畅度优化

流畅度对于任何产品来说其重要性不言而喻,相对于iPhone,Android手机的一个诟病就是卡…为了在后续的开发中避免卡顿问题,细读了腾讯TMQ专行测试团队出品的《移动App性能评测与优化》,本文内容是阅读此书的笔记。

评判流畅度的标准

FPS

FPS:Frames per second,计算方法(来自当我们讨论流畅度的时候,我们究竟在说什么?)

FPS = (v2 - v1) / (t2 - t1);

即每秒绘制次数。FPS并不能很好地反应一个App的卡顿程度,因为它不适用于绝大多数非连续绘制的应用。(有时候App是静态页面,并没有绘制,所以可能很流畅,但是FPS却很低)

流畅度(SM)

SM的计算方法(来自当我们讨论流畅度的时候,我们究竟在说什么?):

SM = (60* totalSeconds - totalSkippedFrames) / totalSeconds;

它反映的是丢帧的数量(60 - SM),可以很好的弥补 FPS 无法准确刻画非连续绘制的应用显示性能的缺陷。

卡顿的原因

导致应用卡顿的原因有很多,UI布局不合理的布局问题,Lint代码分析中建议修改的代码问题,App逻辑中存在的逻辑问题,IO操作不合理的IO问题。

UI布局问题

  1. 过度绘制(去除多余的背景)
  2. 没有用的父布局(可用merge标签解决)
  3. 布局层次过深(使用线性布局导致,可用RelativeLayout代替LinearLayout)
  4. 不常用的UI被设置为GONE(使用ViewStup代替)

Lint分析代码问题

  1. DrawAllocation:避免在绘制或者解析布局(draw/layout)时分配对象,比如在onDraw()中实例化Paint对象。
  2. Wakelock:手机不能进入休眠状态,导致手机一直保持高耗电状态。
  3. Recycle:某些资源,比如TypedArrays、V嗯咯cityTrackers,用完之后应该被回收,但是忘记回收。
  4. ObsoleteLayoutParam:Layout中无用的参数。
  5. UseCompoundDrawables:可优化的布局,包含一个ImageView和一个TextView的线性布局可悲CompoundDrawable的TextView代替。
  6. HandlerLeak:Handler的使用不当导致内存泄漏。
  7. UseSparseArrays:尽量使用Android的SparseArray代替HashMap。
  8. UseValueOf:需要常量时不应该直接new,应该用ValueOf转换。比如需要整数42的对象,不要直接new Integer(42),应该使用Integer.valueOf(42),这样可以省内存。
  9. DisableBaselineAlignment:如果LinearLayout被用于嵌套的layout空间计算,它的android:baselineAligned属性应该被设置成false,以加速layout计算。
  10. InefficientWeight:当线性布局里面只有一个控件,并且使用了weight的时候,最好把width和height设置为0,这样可以省略布局的measure过程。
  11. FloatMath:使用FloatMap代替Math。
  12. nestedWeights:避免嵌套weight,那将拖累执行效率。
  13. UnuseResources/UnusedIds:未被适应的资源会使程序变大,并且编译速度降低。
  14. Overdraw:如果RootView指定一个背景Drawable,会先用Theme的背景绘制一遍,然后才用指定的背景,可以设置theme的backgroud为null来解决
  15. UselessLeaf/UselessParent:View或者View的父亲没有用,应该把它移除,避免加深布局的层次。
  16. UnusedNamespace:有些布局没有必要使用namespace,会影响代码执行效率。

App逻辑问题

  1. 主线程的耗时操作
  2. 执行主线程时,其它线程抢占CPU

IO层问题

  1. UI线程中频繁读写磁盘
  2. 读写内容重复

流畅度优化经验

布局原则

  1. 尽量多使用RelativeLayout代替LinearLayout。
  2. 布局层次一样时,使用LinearLayout代替RelativeLayout,因为LinearLayout性能要高一些。
  3. 将可复用的组件抽取出来并通过include标签使用。
  4. 动态地inflation view性能要比setVisiblity性能要好,使用VIewStup是最好的选择。
  5. 使用merge标签减少布局的嵌套层次。
  6. 去除多余的背景颜色,减少过度绘制。
  7. 使用Compound Drawables(包含图片的TextView)
  8. 嵌套使用包含layout_weight属性的LinearLayout会在绘制时花费昂贵的系统资源,因为每个子组件都需要被测量两次。在使用ListView和GridView的时候这个问题尤为重要,因为子组件会被重复创建,所以要尽量避免使用layout_weight。

ListView优化

  1. 复用convertView。
  2. 异步加载图片。
  3. 快速滑动时不显示图片。
  4. item要尽可能减少控件和布局的层次。ListView的背景色与cacheColorHint设置为相同颜色,可以提高滑动时的渲染性能。
  5. getView方法中不能做复杂的逻辑计算,特别是数据库访问和网络访问操作。

UI线程优化

  1. 不要阻塞UI线程:占用CPU较多的数据库操作尽可能在独立线程进行,如果频繁创建线程,考虑使用线程池。
  2. 不要在UI线程之外操作UI

卡顿优化的分析工具

GPU过度绘制+Trace for OpenGL -> 解决过度绘制
Hierarchy Viewer -> 查找UI布局不合理的地方
Traceview,Systrace -> 代码逻辑分析
StrictMode -> IO问题,UI线程中的IO操作,内存泄漏

关于流畅度问题的思考

卡顿的根本原因应该只有两个,一是CPU处理不过来(UI线程),二是GPU绘制处理不过来。从CPU的方向考虑,线程抢占,内存不足(内存泄漏等)过高导致频繁GC,UI布局问题导致mesure、layout耗时过多,UI线程中的耗时操作等;而绘制处理不过来,应该是过度绘制导致的。

参考资料

《移动App性能评测与优化》
当我们讨论流畅度的时候,我们究竟在说什么?

你可能感兴趣的:(android,性能优化)