专栏首页编码前线BlockCanary原理分析

BlockCanary原理分析

概述

BlockCanary是Android平台上的一个轻量的,非侵入式的性能监控组件,可以在使用应用的时候检测主线程上的各种卡顿问题,并可通过组件提供的各种信息分析出原因并进行修复。

使用

项目地址:https://github.com/markzhai/AndroidPerformanceMonitor

Step1. 配置build.gradle

dependencies {    // most often used way, enable notification to notify block event    implementation 'com.github.markzhai:blockcanary-android:1.5.0'
    // this way you only enable BlockCanary in debug package    // debugImplementation 'com.github.markzhai:blockcanary-android:1.5.0'    // releaseImplementation 'com.github.markzhai:blockcanary-no-op:1.5.0'}

Step2. 在Application中注册

public class DemoApplication extends Application {    @Override    public void onCreate() {        // ...        // Do it on main process        BlockCanary.install(this, new BlockCanaryContext()).start();    }}

Step3. 检测结果

原理

在Android中,应用的卡顿,主要是在主线程阻塞导致的。Looper是主线程的消息调度者,所以以它为突破点。

Looper#loop()

在Looper的loop方法中,有一个Printer,它在每个Message处理的前后被调用,而如果主线程卡住了,就是 dispatchMessage里卡住了。

public static void loop() {    // ....
    for (;;) {        // ...
        // This must be in a local variable, in case a UI event sets the logger        final Printer logging = me.mLogging;        if (logging != null) {            logging.println(">>>>> Dispatching to " + msg.target + " " +                            msg.callback + ": " + msg.what);        }
        // ...        msg.target.dispatchMessage(msg);        // ...
        if (logging != null) {            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);        }       // ...    }}

获取主线程的Looper

因为Looper在每个线程最多只有一个实例,所以只要获取到主线程的Looper,就可以设置一个自定义的Printer对象到里面。

Looper mainLooper = Looper.getMainLooper();

创建自定义Printer

在Printer的println方法去计算主线程一条Message处理的时长,当时长超过设定的阈值时就判定是卡顿了。

...@Overridepublic void println(String x) {    if (!mStartedPrinting) {        mStartTimeMillis = System.currentTimeMillis();        mStartThreadTimeMillis = SystemClock.currentThreadTimeMillis();        mStartedPrinting = true;    } else {        final long endTime = System.currentTimeMillis();        mStartedPrinting = false;        if (isBlock(endTime)) {            notifyBlockEvent(endTime);        }    }}
private boolean isBlock(long endTime) {    return endTime - mStartTimeMillis > mBlockThresholdMillis;}...

设置自定义Printer到主线程Looper

Looper.getMainLooper().setMessageLogging(mainLooperPrinter);

流程图

参考链接

  1. [BlockCanary — 轻松找出Android App界面卡顿元凶]https://blog.zhaiyifan.cn/2016/01/16/BlockCanaryTransparentPerformanceMonitor/

本文分享自微信公众号 - 编码前线(gh_acef1225aadd),作者:辉天神龙

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-03-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • BlockCanary原理分析

    用户1205080
  • docker底层原理介绍

    Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。

    用户1205080
  • Java注解处理器

    接下来我们模仿ButterKnife 实现一个@BindView的注解来了解Java注解处理器的使用。

    用户1205080
  • 《Java从入门到放弃》JavaSE入门篇:网络编程(入门版)

    十方上下
  • python源码阅读笔记之GC(一)

    python源码阅读: 参考书籍:《python源码剖析》 摘要:写这个系列的目的呢,是想为python的学习画上一个暂时的句号,接下来的重点应该是scala这...

    哒呵呵
  • 10分钟教你用Python实现微信翻译机器人

    今天,利用Python爬虫等知识,教大家打造一个微信下的翻译小助手。好吧,开始干活。

    短短的路走走停停
  • Spring中的@Qualifier注解你会用吗

    本文小胖哥将带你来了解一下Spring中的@Qualifier注解,它解决了哪些问题,以及如何使用它。我们还将了解它与@Primary注解的不同之处。

    码农小胖哥
  • 如何监测多云环境

    在当今业务快速增长的市场中,用户希望其应用程序始终可用并保持最新状态,这通常说起来容易做起来难。满足这一需求通常涉及迁移到云平台,这提供了更高的可扩展性和灵活性...

    静一
  • SpringBoot 整合 Nacos Config 实现配置文件动态更新

    Springboot 2.2.2.RELEASE Nacos config 0.2.7

    Alone88
  • 码农西游 | 为啥有些大公司技术弱爆了

    代码写的一团糟,全是复制粘贴,连作者都没改,大家普遍不写注释,也不格式化,代码歪歪扭扭。

    良月柒

扫码关注云+社区

领取腾讯云代金券