性能优化,基本每位 Android 开发都需要考虑这个问题。像这些都是大家常用的性能检测工具,而这次我要讲的是 BlockCanary,由于这个库很久没更新了,所以可能很多人不认识,但是这并不妨碍我们去理解它的实现原理。
OK,开始吹水正文
首先,先祭出GitHub地址
https://github.com/markzhai/AndroidPerformanceMonitor
该库的功能主要为检测在主线程运行的操作时长,假如运行超过一定时间(默认为1000毫秒),则会记录 block 信息并提示给开发者。
集成步骤
- 加上依赖
- 在自定义的 Application 的 onCreate() 方法中进行初始化
- 别忘了在 AndroidMainfest.xml 中进行 Application 绑定
具体检测效果
- 先看看布局效果,就一个按钮
- 对按钮进行监听并点击后睡眠 2000 毫秒
- 点击后,BlockCanary 收集到的信息
是不是很神奇,能够定位到阻塞的位置和阻塞的时间。

使用总结
- 能够计算在主线程中运行方法的时长
- 定位运行的方法在代码上的位置
所以只要解决了以上两个问题,我们就可以自己手写个简单的 BlockCanary 了。
运行时长
em…在主线程中的运行时长…主线程…主线程…
哦!

由于 ActivityThread 被 MainLooper 一直死循环,所以在主线程运行操作基本都是通过 post 消息到 MessageQueue 中,由 MainLooper 取出并执行,那我们可以在执行前记录时间 A,在执行后也记录时间 B,B - A 得到的便是运行时长!

好,我们来看看 Looper 的 loop() 源码:

这不就是我们想要的吗,在执行方法前进行输出,在执行方法后再进行输出。
我们来看看 me.mLogging 是怎么赋值的。
me 调用 myLooper() 获取
所以 mLogging 其实就是当前 Looper 的 mLogging
OK,思路我们有了,只要调用 setMessageLogging 进行赋值,并重写 Printer 的 println() 方法,到时 Looper 就会自动调用我们的 println() 方法了
完整代码:
运行 App,点击按钮:
可以看到,只要在主线程执行方法的时候,都会调用我们的 println() 方法,但是,我们只是为了检测耗时较长的方法即可,所以多加一个拦截:
运行后,点击:

第一部分功能完成了,我们可以开始第二部分了:
定位代码
em…

这块代码我是从 BlockCanary 源码搬过来进行调整后,由于就是一些 SDK 方法的调度,能讲解的不多:
运行,点击后的效果:
由上可以看出,确实是输出了当前的线程的栈信息。

不过,仔细看下,不太对劲啊,为什么没有定位到 clickView() 方法,不是它阻塞的吗?

em…
想想也正常,因为第二次调用 println() 方法的时候,clickView() 已经执行完出栈了,自然不会输出 clickView() 的信息,所以,我们必须在 clickView() 执行的时候就要输出栈信息,也就是在 minTime 时间前,我这里选取的时间为 minTime * 0.8。怕你们忘了 minTime 是什么,提示下:
所以,我们在 printerStart 为 true 的时候,就使用 handler 发送一个 minTime * 0.8 的延迟消息,用于记录此时栈信息,假如 printerStart 为 false 的时候,执行总时间短于 minTime,我们就不输出,否则就输出栈信息。
- 初始化Handler
- 将获取栈消息功能单独抽取出来
- runnable 的发送和销毁
- 运行,点击效果:

终于输出正确的栈信息了!!!
另外,这里再提个额外的信息:
在新版的 LeakCanary 中,只要进行依赖,不需要在 Application 中进行初始化就可以直接使用了!
既然我们也是要写个性能检测工具,那我们也可以参考该做法进行实现。
其实,就是在 ContentProvider 的 onCreate() 方法中进行初始化,因为 App 在启动的时候,是优先初始化 ContentProvider 再初始化 Application 的。具体代码我就不贴了,不难,只是给还未了解到这块的同学多传输些信息。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/163557.html