好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Android消息机制中Message常用的几种监控方式

本篇文章主要是讲解Android消息机制中 Message 执行的几种监控方式:

Printer 监听 Message 执行的起始时机 Observer 监听 Message 执行的起始时机并将 Message 作为参数传入 dump 方式打印消息队列中 Message 快照

上面几种方式各有其优缺点及适用场景,下面我们一一进行分析(其中,Android SDK32中 Looper 的源码发生了一些变化,不过不影响阅读)。

Printer方式

对应 Looper 源码中的:

我们直接深入到 Looper 的核心方法 loopOnce() (基于SDK32的源码)进行分析:

 
private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next(); // might block
    ...
    final Printer logging = me.mLogging;
    if (logging != null) {
        logging.println(">>>>> Dispatching to " + msg.target + " "
                + msg.callback + ": " + msg.what);
    }
    long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
    try {
        msg.target.dispatchMessage(msg);
        ...
    }
    ...
    if (logging != null) {
        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
    }
    ...
    msg.recycleUnchecked();
    return true;
} 

其中 msg.target.dispatchMessage() 就是我们消息分发执行的地方,而在这个执行前后都会调用 Printer.println() 方法。

所以如果我们能够将这个 Printer 对象替换成我们自定义的,不就可以监听 Message 执行和结束的时机,所幸, Looper 也确实提供了一个方法 setMessageLogging() 支持外部自定义 Printer 传入:

 public void setMessageLogging(@Nullable Printer printer) {
    mLogging = printer;
} 

这个有什么用呢,比如可以用来监听耗时的 Message ,从而定位到业务代码中卡顿的代码位置进行优化, ANRWatchDog 据我所知就使用了这样的原理。

Observer方式

这个定位到 Looper 源码中就是:

可以看到这个接口提供的方法参数更加丰富,我们看下它在源码中的调用位置(精简后的代码如下):

 
private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) {
    Message msg = me.mQueue.next(); // might block
    final Observer observer = sObserver;
    Object token = null;
    if (observer != null) {
        token = observer.messageDispatchStarting();
    }
    try {
        msg.target.dispatchMessage(msg);
        if (observer != null) {
            observer.messageDispatched(token, msg);
        }
    } catch (Exception exception) {
        if (observer != null) {
            observer.dispatchingThrewException(token, msg, exception);
        }
        throw exception;
    }
} 

和上面的 Printer 调用有点相似,也是在 消息执行前、消息执行后 调用,其中执行后分为两种:

正常执行后调用 messageDispatched() ; 异常执行后调用 dispatchingThrewException() ;

下面我们简单的介绍 Observer 这三个接口方法:

messageDispatchStarting() 在 Message 执行之前进行调用,并且可以返回一个 标识 来标识这条 Message 消息,这样当消息正常执行结束后,调用 messageDispatched() 方法传入这个标识和当前分发的 Message ,我们就可以建立这个标识和 Message 之间的映射关系;出现异常的时候就会调用 dispatchingThrewException() 方法,除了传入标识和分发的 Message 外,还会传入捕捉到的异常。

不过很遗憾的是, Observer 是个被 @Hide 标记的,不允许开发者进行调用,如果大家真要使用。

dump方式

这个可以打印当前消息队列中每条消息的快照信息,可以根据需要进行调用:

1 . Looper.dump() :

 public void dump(@NonNull Printer pw, @NonNull String prefix) {
    pw.println(prefix + toString());
    mQueue.dump(pw, prefix + "  ", null);
} 

2 . MessageQueue.dump()

 void dump(Printer pw, String prefix, Handler h) {
    synchronized (this) {
        long now = SystemClock.uptimeMillis();
        int n = 0;
        for (Message msg = mMessages; msg != null; msg = msg.next) {
            if (h == null || h == msg.target) {
                pw.println(prefix + "Message " + n + ": " + msg.toString(now));
            }
            n++;
        }
        pw.println(prefix + "(Total messages: " + n + ", polling=" + isPollingLocked()
                + ", quitting=" + mQuitting + ")");
    }
} 

很直观的可以看到,当调用 dump() 方法时会传入一个 Printer 对象实例,就会遍历消息队列 mMessages ,通过传入的 Printer 打印每条消息的内容。

其中 Message 重写了 toString() 方法:

大家可以根据需要自行使用。

查看更多关于Android消息机制中Message常用的几种监控方式的详细内容...

  阅读:49次