源码角度聊聊BlockCanary的原理,android移动应用开发答案

2.ActivityThread的内部类H


我们以Activity为例,我们知道Activity的所有的生命周期都是运行在主线程的,为什么呢?

我们来看看哈。

ActivityThread内部成员变量mH,这个mH看下代码其实就是个Handler,它的类型是有ActivityThread的内部类H决定的。

我们来看看这个H的源码。

private class H extends Handler {

//定义了各种消息类型

public static final int LAUNCH_ACTIVITY = 100;

public static final int PAUSE_ACTIVITY = 101;

public s
tatic final int PAUSE_ACTIVITY_FINISHING= 102;

public static final int STOP_ACTIVITY_SHOW = 103;

public static final int STOP_ACTIVITY_HIDE = 104;

public static final int RESUME_ACTIVITY = 107;

public static final int SEND_RESULT = 108;

public static final int RESUME_ACTIVITY = 107;

public static final int SEND_RESULT = 108;

public static final int DESTROY_ACTIVITY = 109;

public static final int BIND_APPLICATION = 110;

public static final int EXIT_APPLICATION = 111;

public static final int NEW_INTENT = 112;

public static final int RECEIVER = 113;

public static final int CREATE_SERVICE = 114;

public static final int SERVICE_ARGS = 115;

public void handleMessage(Message msg) {

if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));

switch (msg.what) {

case LAUNCH_ACTIVITY: {

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, “activityStart”);

final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

r.packageInfo = getPackageInfoNoCheck(

r.activityInfo.applicationInfo, r.compatInfo);

//启动Activity 最后会回调Acitivty的onCreate方法。

handleLaunchActivity(r, null, “LAUNCH_ACTIVITY”);

} break;

case RELAUNCH_ACTIVITY: {

ActivityClientRecord r = (ActivityClientRecord)msg.obj;

handleRelaunchActivity®;

} break;

case PAUSE_ACTIVITY: {

//启动Activity 最后会回调Acitivty的onPause方法。

handlePauseActivity((IBinder) args.arg1, false,

(args.argi1 & USER_LEAVING) != 0, args.argi2,

(args.argi1 & DONT_REPORT) != 0, args.argi3);

} break;

}

}

看了H的代码,大多数朋友肯定都已经知道了。为什么Activity,Service这些组件的生命周期都是运行在主线程呢。其实都是与这个mH息息相关的。这个mH是与主线程的Looper对象进行绑定的,通过这个mH发送过来的消息都是执行在主线程的。Activity,Service这些组件的生命周期方法都是在mH的handlerMessage方法内部进行回调。这里解释一下哈,Android中我们所说的主线程其实就是ActivityThread的main方法所执行的线程,并不是ActivityThread本身哦。

所以换句话说检测主线程卡顿,我们只要检测每个消息执行的时长就可以了。Android内部其实已经为我们提供了一个方法,这就是BlockCanary的原理哦。

3.Looper.loop()


Handler机制我们最熟悉不过了,就不多说了,我们直接看看Looper.loop()方法实现,其中必有蹊跷。

public static void loop() {

…//省略部分代码

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

final Printer logging = me.mLogging;

if (logging != null) {

//第一次打印

logging.println(">>>>> Dispatching to " + msg.target + " " +

msg.callback + ": " + msg.what);

}

try {

//分发消息,处理消息。target就是发送消息的Handler

msg.target.dispatchMessage(msg);

end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();

} finally {

if (traceTag != 0) {

Trace.traceEnd(traceTag);

}

}

…//省略部分代码

if (logging != null) {

//消息处理结束第二次打印

logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);

}

}

}

这里我们看到了重要的东西了哈,消息处理前会调用一个logging.println()方法,消息分发给Handler处理结束后,还会=调用一次logging.println()方法。这两次println()方法调用的时间间隔,不就是是我们主线程一条消息处理的时长么?那我们只要把logging这个对象替换程我们自己的不就好了嘛?

前面ActivityThread 的main方法中有一句这个代码: Looper.myLooper().setMessageLogging(new

LogPrinter(Log.DEBUG, “ActivityThread”));

这个方法干嘛的?其实就是set这个logging对象的!

我们来看看这个句代码:

public void setMessageLogging(@Nullable Printer printer) {

//直接把传进来的值,赋值给mLogging对象了

mLogging = printer;

}


4.BlockCanary的实现


public void setMessageLogging(@Nullable Printer printer) {

//直接把传进来的值,赋值给mLogging对象了

mLogging = printer;

}


4.BlockCanary的实现


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值