本文部分内容借鉴自http://blog.csdn.net/lmj623565791/article/details/58626355
卡顿检测
- 利用loop()
Android系统中,UI线程(即主线程)负责管理更新UI内容,为了避免UI线程阻塞,一般不会在其中进行耗时操作。但是,人总是会有疏忽的时候,那么就可以通过利用UI线程里面的loop()打印日志来监测是否进行了耗时操作。
loop()取出Message的代码大致如下
public static void loop() {
final Looper me = myLooper();
final MessageQueue queue = me.mQueue;
// ...
for (;;) {
Message msg = queue.next(); // might block
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// focus
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// ...
}
msg.recycleUnchecked();
}
}
我们需要知道的是
msg.target.dispatchMessage(msg);
这段代码的运行时间。这段代码前后的日志正是辅助我们获取运行时间的手段,通过计算两个日志的时间差,我们就能得出运行时间,如果该时间超过了既定的阈值,我们就进行后续的操作。
- 利用Choreographer
为了保证屏幕60Hz的刷新频率,Android系统需要每隔16ms发送一次VSYNC信号,进行UI渲染。SDK中包含了一个相关类,以及相关回调。理论上来说两次回调的时间周期应该在16ms,如果超过了16ms我们则认为发生了卡顿。
卡顿原因及解决
- 过度复杂的UI布局
如果UI布局层次太深,比如过多的layout嵌套,或者自定义控件的onDrow中包含了复杂运算就可能增加渲染UI的工作量,导致出现卡顿。
解决方法:简化布局,避免复杂运算。
- 过度绘制
手机屏幕的每一个像素点只能显示一个颜色,但是却可能被多次绘制。比如一个button控件,默认主题会有一个背景,在做自定义的时候我们会手动设置一个背景,那么这个button控件的像素点实际上就被绘制了两次。如果要是button嵌套在某个layout里面,该layout也有自己的背景,那就更多了。
解决方法:注意像素的过度绘制,避免绘制不可见的背景。
- UI线程的复杂运算
将耗时操作放在UI线程中,比如网络请求。
解决方法:开启服务,让后台服务帮助完成耗时操作。
- 频繁的GC
大量的对象被瞬间创建,短时间内又被释放。
解决方法:避免此类操作。