App优化 - 消除卡顿优化

前言

  1. App优化 - 需要优化哪些?
  2. App优化 - 性能分析工具
  3. App的3种启动方式
  4. App优化 - App启动速度优化
  5. App优化 - 布局优化
  6. App优化 - 消除卡顿优化
  7. App优化 - ANR优化
  8. App优化 - 电池省着用
  9. App优化 - 网络优化

1. 感知卡顿


用户之所以会感觉到卡顿,是界面刷新的原因,界面性能取决于UI渲染性能,如果UI过于复杂,或者实现不够好,设备也不给力,界面就会卡顿,给用户卡顿的感觉。

1.1>:16ms原则?

Android系统每隔16ms会发出 vsync信号,重绘界面(Activity);

1.2>:16ms原因?

因为Android的刷新率是60FPS(Frame Per Second),即就是每秒60帧的刷新率,约16ms刷新一次,如下图所示;


App优化 - 消除卡顿优化_第1张图片
图片.png
上图意思就是:

每隔16ms重绘一次Activity界面,每隔16ms重绘一次Activity界面,每隔16ms重绘一次Activity界面;
也就是说我们需要在16ms之内要完成下一次刷新界面的所有相关的运算和操作,来重绘解Activity界面,如果16ms没有完成需要刷新界面的 相关运算和操作,就会导致丢帧、用户感觉界面卡顿,如果界面过于复杂,丢帧会更多,卡到爆。

1.3>:举例

1>:比如我们更新屏幕背景图片,需要24ms来完成运算和操作,当系统在第一个16ms刷新Activity界面时,因为还没运算完,所以不能绘制出图片,当系统下一次再发出 vsync信号重绘界面时,可以重绘界面,用户能看到更新后的图片,也就是说32ms后看到刷新而不是24ms,这个叫做丢帧;
2>:丢帧给用户感觉就是卡顿,如果运算复杂,丢帧会更多,界面会停滞不前,卡到爆;

2. 卡顿原因?


2.1:布局过于复杂

界面性能取决于UI渲染性能,UI渲染由CPU和GPU两个部分共同完成;

CPU处理内存,负责执行onMeasure()、onLayout()、onDraw()等一些运算;
GPU处理界面,负责将UI绘制到界面上;

如果UI布局层次太深,或者自定义View中的onDraw()方法有复杂的计算,CPU运算可能大于16ms,导致卡顿;
可以使用Hierarchy Viewer工具分析布局,以图形化树状结构展示UI层级,会对每个节点给出三个小圆点,表示该元素的onMeasure()、onLayout()、onDraw()的耗时及性能;

2.1:过度绘制(Overdraw)

定义: overdraw:同一个像素点被绘制多次

理想情况是,每一个界面中每一帧,每一个像素点,应该只能被绘制一次,如果有多次绘制,就是Overdraw过度绘制了;

2.1:调试Overdraw

手机 -> 开发者选项 -> 调试GPU过度绘制,有5种颜色:
原色:没有被绘制overdraw;
蓝色:只绘制1次overdraw;
绿色:绘制2次overdraw;
粉色:绘制3次overdraw;
红色:绘制4次overdraw;
一般是:蓝色性能比较优的;

2.2:Overdraw的分析

常见就是:
1>:绘制多重布局
在xml布局文件中,background属性在根布局和子布局中重复设置
举例如下:


App优化 - 消除卡顿优化_第2张图片
图片.png

中间的ViewPager设置了background属性:


ViewPager所在的根布局的也设置了background属性:



    ...

解决方法就是:这两个background属性任意去掉一个就可以,因为两个background同时都给ViewPager设置了背景,所以需要去掉一个,效果如下:


App优化 - 消除卡顿优化_第3张图片
图片.png
注意:

过度绘制overdraw主要原因就是背景多重绘制。多重绘制原因就是在根布局及子布局中多次使用同一个background属性,一般建议把background属性写到 根布局中就ok,这样就可以避免 过度绘制overdraw。

2.3:UI线程的复杂运算

StrictMode:基于线程或者VM设置的策略,用于检测主线程的磁盘读写、网络访问等耗时操作;一旦检测到线程违例,控制台就会输出一些警告,包含一个trace信息,它会展示你的应用在什么地方出现的问题;
用法:
在BaseApplication中的onCretate()中开启 StrictMode:

public void onCreate() {
    if (BuildConfig.DEBUG) {
        // 针对线程的相关策略
        StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                .detectDiskReads()
                .detectDiskWrites()
                .detectNetwork()   // or .detectAll() for all detectable problems
                .penaltyLog()
                .build());
                
        // 针对VM的相关策略
        StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                .detectLeakedSqlLiteObjects()
                .detectLeakedClosableObjects()
                .penaltyLog()
                .penaltyDeath()
                .build());
    }
    super.onCreate();
}
注意:

如果线程出现问题,会在控制台输出警告,能定位到具体代码

2.4:频繁的GC原因?

执行GC操作的时候,任何线程的任何操作都会需要暂停,等GC操作完之后其他操作才可以进行,所以说频繁的GC会导致界面卡顿

导致频繁的GC有2个原因:

1>:内存抖动:大量对象被创建,又在短时间内马上释放;
2>:瞬间产生大量对象,会严重占用Young Generation内存。当达到阈值,剩余空间不够时,也会触发GC。即使每次分配的对象需要占用很少的内存,但它们叠加在一起会增加Heap的压力,从而触发更多的GC,结果就是可能造成丢帧,会让用户感受到卡顿;

瞬间产生大量对象的场景:

1>:循环new对象;
2>:onDraw()方法中new对象;

你可能感兴趣的:(App优化 - 消除卡顿优化)