您当前的位置: 首页 >  ar
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

性能优化专题十三--BlockCanary简析

沙漠一只雕得儿得儿 发布时间:2020-06-27 16:15:26 ,浏览量:0

BlockCanary使用:

build.gradle添加BlockCanary依赖,如下:

implementation 'com.github.markzhai:blockcanary-android:1.5.0'

在Application中注册:

BlockCanary.install(this, new AppBlockContext()).start();

注意AppBlockContext是我们继承自BlockCanaryContext,重写其中的一些方法,就可以定制我们自己的一些阈值,例如卡顿阈值我们设置为3秒,卡顿输出路径等等:

class AppBlockContext extends BlockCanaryContext {
    // 实现各种上下文,包括应用标示符,用户uid,网络类型,卡慢判断阙值,Log保存位置等

    /**
     * Implement in your project.
     *
     * @return Qualifier which can specify this installation, like version + flavor.
     */
    public String provideQualifier() {
        return "unknown";
    }

    /**
     * Implement in your project.
     *
     * @return user id
     */
    public String provideUid() {
        return "uid";
    }

    /**
     * Network type
     *
     * @return {@link String} like 2G, 3G, 4G, wifi, etc.
     */
    public String provideNetworkType() {
        return "unknown";
    }

    /**
     * Config monitor duration, after this time BlockCanary will stop, use
     * with {@code BlockCanary}'s isMonitorDurationEnd
     *
     * @return monitor last duration (in hour)
     */
    public int provideMonitorDuration() {
        return -1;
    }

    /**
     * Config block threshold (in millis), dispatch over this duration is regarded as a BLOCK. You may set it
     * from performance of device.
     *
     * @return threshold in mills
     */
    public int provideBlockThreshold() {
        return 1000;
    }

    /**
     * Thread stack dump interval, use when block happens, BlockCanary will dump on main thread
     * stack according to current sample cycle.
     * 

* Because the implementation mechanism of Looper, real dump interval would be longer than * the period specified here (especially when cpu is busier). *

* * @return dump interval (in millis) */ public int provideDumpInterval() { return provideBlockThreshold(); } /** * Path to save log, like "/blockcanary/", will save to sdcard if can. * * @return path of log files */ public String providePath() { return "/blockcanary/"; } /** * If need notification to notice block. * * @return true if need, else if not need. */ public boolean displayNotification() { return true; } /** * Implement in your project, bundle files into a zip file. * * @param src files before compress * @param dest files compressed * @return true if compression is successful */ public boolean zip(File[] src, File dest) { return false; } /** * Implement in your project, bundled log files. * * @param zippedFile zipped file */ public void upload(File zippedFile) { throw new UnsupportedOperationException(); } /** * Packages that developer concern, by default it uses process name, * put high priority one in pre-order. * * @return null if simply concern only package with process name. */ public List concernPackages() { return null; } /** * Filter stack without any in concern package, used with @{code concernPackages}. * * @return true if filter, false it not. */ public boolean filterNonConcernStack() { return false; } /** * Provide white list, entry in white list will not be shown in ui list. * * @return return null if you don't need white-list filter. */ public List provideWhiteList() { LinkedList whiteList = new LinkedList(); whiteList.add("org.chromium"); return whiteList; } /** * Whether to delete files whose stack is in white list, used with white-list. * * @return true if delete, false it not. */ public boolean deleteFilesInWhiteList() { return true; } /** * Block interceptor, developer may provide their own actions. */ public void onBlock(Context context, BlockInfo blockInfo) { } }
Looper 提供的机制

通过Hander.postMessage发送一个消息给主线程(sMainLooper.loop),主线程会通过轮训器Looper不断的轮训MessageQueue中的消息队列,通过queue.next方法获取消息队列中的消息,然后我们计算出调用dispatchMessage方法的前后时间值(T1,T2),通过T2减去T1的时间差来判断是否超过我们之前设定好的阈值,如果超过了我们设定的阈值,我们就dump出我们收集的信息,来定位我们UI卡顿的原因。

在Looper的loop方法中,有一个Printer,它在每个Message处理的前后被调用,而如果主线程卡住了,就是 dispatchMessage里卡住了,里面实现的功能就是不断地从 MessageQueue 里面取出 Message 对象,并加以执行。

for (;;) {
    Message msg = queue.next(); // might block
    if (msg == null) {
        // No message indicates that the message queue is quitting.
        return;
    }

    // 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);
    }

    msg.target.dispatchMessage(msg);

    if (logging != null) {
        logging.println("            
关注
打赏
1657159701
查看更多评论
0.1212s