Android App-BlockCanary
目录
1. BlockCanary介绍 2
1.1 功能 3
2. 为什么要使用BlockCanary? 4
3.1配置 build.gradle文件 5
3.2 新建一个类,继承自BlockCanaryContext,实现自己的监控上下文,代码示意如下 5
3.3 初始化Block的配置信息 6
3.4 检测卡顿 6
4.原理 9
5. 总结 12
- BlockCanary介绍
BlockCanary是Android平台上的一个轻量的,非侵入式的性能监控组件,应用只需要简单地加几行,提供一些该组件需要的上下文环境就可以在使用应用的时候检测主线程上的各种卡顿问题,并通过组件提供的各种信息分析出原因并进行修复。
BlockCanary对主线程操作进行了完全透明的监控,并能输出有效的信息,帮助开发分析、定位到问题所在,迅速优化应用。其特点有:
- 非侵入式,简单的两行就打开监控,不需要到处打点,破坏代码优雅性。
- 精准,输出的信息可以帮助定位到问题所在(精确到行),不需要像Logcat一样,慢慢去找。
目前包括了核心监控输出文件,以及UI显示卡顿信息功能。仅支持Android端。
-
- 功能
BlockCanary会在发生卡顿(通过MonitorEnv的getConfigBlockThreshold设置)的时候记录各种信息,输出到配置目录下的文件,并弹出消息栏通知(可关闭)。
简单的使用如在开发、测试的时候,Debug包启用
- 开发可以通过图形展示界面直接看信息,然后进行修复
- 测试可以把log丢给开发,也可以通过卡慢详情页右上角的更多按钮,分享到各种聊天软件
- 生成一堆的log,慢慢过滤记录下重要的卡顿
还可以通过Release包用户端定时开启监控并上报log,比如监控,后台匹配堆栈过滤同类原因,提供给开发更大的样本环境来优化应用。
dump的信息包括:
- 基本信息:安装包标示、机型、api等级、uid、CPU内核数、进程名、内存、版本号等
- 耗时信息:实际耗时、主线程时钟耗时、卡顿开始时间和结束时间
- CPU信息:时间段内CPU是否忙,时间段内的系统CPU/应用CPU占比,I/O占CPU使用率
- 堆栈信息:发生卡慢前的最近堆栈,可以用来帮助定位卡慢发生的地方和重现路径
- 为什么要使用BlockCanary?
App开发:在复杂的项目环境中,由于TS代码庞大,业务复杂,包含各种第三方库,如果偶尔再来个jni调用,不能快速定位问题,所以在出现了卡顿的时候,我们很难定位到底是哪里出现了问题,即便知道是哪一个Activity/Fragment,也仍然需要进去里面一行一行看,数千行的类再加上跳来跳去调来调去的,结果就是不了了之随它去了,实在不行了再优化吧。于是一拖再拖,最后可能压根就改不动了,客户端越来越卡。
事实上,很多情况下卡顿不是必现的,比如在我们的公司APP中,它们可能与机型、环境、操作等有关,存在偶然性,即使发生了,再去查那如山般的logcat,也不一定能找到卡顿的原因,是我们自己的应用导致的还是其他应用抢占资源导致的?是哪些方法导致的?很难去回朔。有些机型自己修改了api导致的卡顿,还必须拿那台机器才能去调试找原因。
BlockCanary就是来解决这个问题的。告别打点和调试,哪里卡顿,一目了然。
3. 如何使用
3.1配置 build.gradle文件
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL9klaNRTRE5UNVpXT1UkMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLyEDN5ATO1MjM4IDNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
compile 'com.github.markzhai:blockcanary-android:1.5.0'
// 仅在debug包启用BlockCanary进行卡顿监控和提示的话,可以这么用
debugCompile 'com.github.markzhai:blockcanary-android:1.5.0'
releaseCompile 'com.github.markzhai:blockcanary-no-op:1.5.0'
3.2 新建一个类,继承自BlockCanaryContext,实现自己的监控上下文,代码示意如下
3.3 初始化Block的配置信息
BlockCanary.install(this, new AppContext()).start();
环境搭建完毕,我们来模拟一个主界面卡顿的代码,用BlockCanary进行检测
3.4 检测卡顿
- 在xml布局中添加一个按钮,来触发模拟卡顿的代码
- 在代码中使主线程阻塞
整个程序界面如下:
当我们点击按钮之后,查看BlockCanary给我们的提示信息:
日志输出:
我们可以清晰的看到,第48行代码就是界面的元凶,我们就可以修改48行的代码来解决界面卡顿的状况.
4.原理
熟悉Message/Looper/Handler系列的同学们一定知道Looper.java中这么一段:
即整个应用的主线程,只有这一个looper,不管有多少handler,最后都会回到这里。
Looper的loop方法中有这么一段
这个Printer - mLogging,它在每个message处理的前后被调用,而如果主线程卡住了,不就是在dispatchMessage里卡住了吗?
该组件利用了主线程的消息队列处理机制,通过
Looper.getMainLooper().setMessageLogging(mainLooperPrinter);
并在mainLooperPrinter中判断start和end,来获取主线程dispatch该message的开始和结束时间,并判定该时间超过阈值(如2000毫秒)为主线程卡慢发生,并dump出各种信息,提供开发者分析性能瓶颈。
- 总结
BlockCanary作为一个Android组件,目前还有局限性,因为其在一个完整的监控系统中只是一个生产者,还需要对应的开发去分析日志,比如归类排序,以便看出哪些卡慢更有修复价值,需要优先处理;又比如需要过滤机型,有些奇葩机型的问题造成的卡慢,到底要不要去修复是要修复。扯远一点的话,完全还能用来做链条监控,比如一个完整的流程是A -> B -> D -> E, 但是某个时间节点突然A -> B -> D后没有到达E,这时候监控就可以发出预警,让开发人员及时定位。