Android 之输出 Handler 日志
今天看到一篇文章提到了给 Looper 加日志以观察 GC,发现这个 Looper 打日志这个小技巧有助于调试 UI 卡顿问题,我们学学这个技巧吧。
通过统计主线程 Looper
中每个 Message 的耗时,很容易找出主线程耗时过多的操作。这些操作往往是导致 UI 卡顿的罪魁祸首。
你可能会说,我在 Handler.handMessage()
中也可以添加计时代码呀,在 Looper
中统计有什么好处?如果是你自己写的 Handler
的确很容易统计,但如果是别人写的呢,如果是第三方库中的呢?另一方面,即便自己写的,如何保证新加的 Handler
不会遗漏计时代码?所以这种做法并不可取。看看更好的做法是怎样的。
setMessageLogging()
注释文档中说,setMessageLogging()
用于当前 Looper 处理 Message 时打印日志。
- 传 null 参数关闭日志功能,传非 null 的
printer
开启日志功能 - 开启日志功能后,会在每个 Message 分发的开始以及结束时输出日志信息到
printer
,具体的日志信息包括区分 Message 的目标 Hander 以及 Message 内容
对照 loop()
方法源码(省略无关部分),跟上面描述一致。所以这里不再赘述。
1 | // android.os.Looper.java |
输出 Handler 日志
界面上有一个使用 Handler
实现的轮播图,每隔5秒发消息切换到下一张图片。我们给它加上日志功能,代码如下:
1 | Looper.getMainLooper().setMessageLogging(new Printer() { |
每次切换图片时会输出如下格式的日志:
1 | 12-12 10:35:38.614 9542-9542 I: >>>>> Dispatching to Handler (com.tc.igame.view.common.fragment.EventCenterFragment$1) {101c258} null: 1 |
Dispatching to Handler
和Finished to Handler
对应首一次 Message 处理过程。我们可以根据这种特定的日志格式为每个 Message 处理加上耗时统计。具体做这可参考《为你的 android 程序加上 gc 监控吧!》,这里不展开。
补充
《为你的 android 程序加上 gc 监控吧!》中提到的 gc 监控做法太过复杂,并不可取。实际上,Android 6.0(API 23)之后 art 虚拟机支持如下方式获取 gc 次数和 gc 耗时:
1 | Debug.getRuntimeStat("art.gc.gc-count"); |
我们直接调用系统 API 即可很方便地获取到 gc 次数和 gc 耗时。
添加如下代码并在 Android Monitor 中强制 gc,观察输出的日志。
1 | Looper.getMainLooper().setMessageLogging(new Printer() { |
GC 日志参考