Android Looper、Message、Handler、MessageQueue源码解析

原创
2016/10/10 10:30
阅读数 390

在Android开发过程中,MessageHandler是经常会使用到的类,我们对它们广泛的认知是为了在异步任务中更新主线程的UI,因为在主线程处理耗时的任务是会ANR的。MessageHandler普遍使用的场景是HTTP请求,HTTP请求可能会造成长时间的线程阻塞,一般来说都是新开一个线程处理请求任务,在数据最终返回的时候调用HandlerhandlerMessage方法,交给主线程处理,但是它们内部是如何运作的呢? 为了搞清楚这个问题,我们先从ActivityThread这个main方法开始,一步一步分析:

public static void main(String[] args) {
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    SamplingProfilerIntegration.start();

    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);

    Environment.initForCurrentUser();

    // Set the reporter for event logging in libcore
    EventLogger.setReporter(new EventLoggingReporter());

    AndroidKeyStoreProvider.install();

    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);

    Process.setArgV0("<pre-initialized>");

    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

将目光聚焦在关键部分,在main方法里,首先调用Looper的静态方法prepareMainLooper,我们来看看prepareMainLooper干了些什么事?

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}

都是一些静态调用,我们追踪下去

private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

sThreadLocal这个静态变量是什么?它的声明和初始化是这样的:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

ThreadLocal这个类从字面意思就应该猜得出来,它可以保存本地线程变量,不受其他线程的干扰。那么,意思就很明确了,prepareMainLooper()方法首先检查本地变量是否保存有值,如果有,则抛异常退出,如果没有,就新建一个Looper实例,作为线程唯一副本保存在ThreadLocal之中,Looper在实例化时,初始化了一个MessageQueue对象,而这个MessageQueue对象,就是消息队列。 剩下的sMainLooper = myLooper()很简单,就是将线程唯一Looper实例变量副本赋值给sMainLooper变量。 接下来有一句神奇的代码:

if (false) {
    Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
}

一脸懵逼 什么鬼?!! 这句代码有什么特殊的考量吗?!!! 我只能认为Google developer们调试后忘了删掉这段代码了

最后就调用Looper.loop()方法了,这个方法是重头戏!

public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    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("<<<<< Finished to " + msg.target + " " + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn't corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, "Thread identity changed from 0x"
                    + Long.toHexString(ident) + " to 0x"
                    + Long.toHexString(newIdent) + " while dispatching to "
                    + msg.target.getClass().getName() + " "
                    + msg.callback + " what=" + msg.what);
        }

        msg.recycleUnchecked();
    }
}

这块代码也很好理解,首先从本地线程也就是主线程取出保存在ThreadLocal里的Looper对实例,然后从Looper里取出MessageQueue实例,然后..然后...没错!你没有看错!!就开始死循环了...然后你会发现,Android主线程就是一个死循环,这个死循环发生在Looper内部,你也可以认为Looper就是这个死循环,它不断的从MessageQueue取出Message,然后执行处理,最后回收Message,Android的主线程就是这个简单,现在你也应该知道为什么我们必须要了解Looper、Message、Handler和MessageQueue,以及透彻他们的工作机制了吧。那么?Activity,Service,Intent,BroadcastReceiver的动作是如何最终变成HandlerMessage的呢?这是一个大坑,以后再填,先抛下这个疑问,我们先看看这三个方法:

不断从MessageQueue取出Message的方法:

Message msg = queue.next();

执行处理Message的方法:

msg.target.dispatchMessage(msg);

回收Message的方法:

msg.recycleUnchecked();

第一个方法比较复杂,我们先解析执行处理Message的方法msg.target.dispatchMessage(Message msg)msg.target变量是个Handler对象,它从何而来呢?这个问题还得从我们发送一个Message开始说起。

通常我们发送一个Message是酱紫的:

Handler handler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        // do something
    }
};
Message message = handler.obtainMessage();
handler.sendMessage(message);

进入Handler.obtainMessage()方法:

public final Message obtainMessage()
{
    return Message.obtain(this);
}

Google Coder的开发人员有精神分裂么?这花括号...

再进入Message.obtain(Handler handler)方法:

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;

    return m;
}

好吧,原来target变量就是Handler.obtainMessage()这个Handler对象。那么,我们大致明白了,MessageQueue循环取出Message,每个Message都带着一个Handler,由HandlerdispatchMessage(Message msg)来处理该消息。辣么,Handler如何处理这个消息的呢?

来看看dispatchMessage(Message msg)方法:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

从源码中可以看出最终执行的地方有三处,先后为:msg.callback, mCallback.handleMessage(msg)handleMessage(msg)handleMessage(msg)好理解,因为通常我们都是复写HandlerhandleMessage(Message msg)来实现我们更新主线程UI的逻辑,另外两个就比较陌生了,我们一一解析。

msg.callback赋值的地方在两处:

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    m.obj = token;
    m.callback = r;
    return m;
}

getPostMessage(Runnable r)getPostMessage(Runnable r, Object token)这个两个方法又是分别在这些地方调用:


public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

public final boolean postAtTime(Runnable r, long uptimeMillis)
{
    return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}

public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

public final boolean postDelayed(Runnable r, long delayMillis)
{
    return sendMessageDelayed(getPostMessage(r), delayMillis);
}

有没有熟悉的感觉?没错,这就是我们经常使用的发送更新主线程UI消息的一种方式:

new Handler().post(new Runnable() {
    @Override
    public void run() {
        // do something
    }
});

post(Runnable r)postAtTime(Runnable r, long uptimeMillis)sendMessageDelayed(Message, delayMillis)......辣么多方法,会不会被搞晕了?

一脸懵逼

我们用一张图来梳理一下这些方法

恩,这下清楚多了。

接下来搜索一下mCallback的出处,其实它是在Handler类的构造函数里被赋值的:


public Handler() {
    this(null, false);
}

public Handler(Callback callback) {
    this(callback, false);
}

public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}

public Handler(boolean async) {
    this(null, async);
}

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

用图表梳理一下它们之间个关系:

从图中就很明显的看出7个构造方法分为两部分,一部分是默认使用本地线程的Looper对象,另一部分是需要传入一个Looper对象,两部分你都可以传入一个Callback回调,它的定义是在Handler类内部之中:

public interface Callback {
    public boolean handleMessage(Message msg);
}

所以才会有mCallback.handleMessage(msg)的调用。所以你的Handler实例可以这样实例化:

new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        return false;
    }
});

new Handler().post(new Runnable() {
    @Override
    public void run() {
        // do something
    }
});

其实是一个道理。

到目前为止,我们已经搞懂了消息是如何被处理的——它是由Handler三个部分:Runnable Callback,Callback Function以及Handler Default handleMessage Method其中之一处理的。现在我们回过头来看看消息是如何从MessageQueue取出来的,但首先我们得知道,Message是如何传入队列的。 由上面发送消息方法的关系图可是知道,无论你是选择哪一种方式发送消息,最终它都会调用enqueueMessage(MessageQueue, Message, long)方法放入队列:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

再进入MessageQueueenqueueMessage(Message, long)方法看看:

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                    msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        msg.markInUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            // New head, wake up the event queue if blocked.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            // Inserted within the middle of the queue.  Usually we don't have to wake
            // up the event queue unless there is a barrier at the head of the queue
            // and the message is the earliest asynchronous message in the queue.
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

代码有点长,我们从msg.when = when这一段开始读起,第一个问题就来了,mMessage是干什么的?它的变量声明其实是个Message对象,它有什么作用呢?往下看,有个注释暗示了它的作用——New head, wake up the event queue if blocked.意思就不言而喻了,mMessage就是MessageQueue消息队列的队列头,往下看接下来的判断语句:

if (p == null || when == 0 || when < p.when) {
    // New head, wake up the event queue if blocked.
    msg.next = p;
    mMessages = msg;
    needWake = mBlocked;
}

首先我们得知道,每个Message都是有自己的处理时间的——when属性,这个when属性决定了这个MessageMessageQueue的位置(Message是根据when来排列的)以及处理的规定时间点,但是有种Message例外,它的when属性是0,由Handler.sendMessageAtFrontOfQueue(Message)发送,从这个方法的命名就可以知道它的意图——希望这个Message排在队列的头部,也就是希望这个消息能够立刻处理。那么这个判断语句我们也应该知道它的意思了:如果队列头为空或者when为0或者需要处理的时间比队头的时间还要紧迫,则将这个Message作为新的队头

enqueue MessageQueue header 00

enqueue MessageQueue header 01

enqueue MessageQueue header 02

再看看else语句,图我也不画了,意思也简单,从队头往后遍历Message,根据when值将新的Message插入到合适的位置。

看完了MessageQueue.enqueueMessage(Message, long)方法,我们可以探讨一下Message是如何从MessageQueue取出来的了,看源码:

Message next() {
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    int pendingIdleHandlerCount = -1;
    int nextPollTimeoutMillis = 0;
    for (;;) {
        if (nextPollTimeoutMillis != 0) {
            Binder.flushPendingCommands(); // 阻塞的时间可能很长,确保在此期间释放渲染对象的引用,以免占用空间
        }

        nativePollOnce(ptr, nextPollTimeoutMillis); // 轮询, 阻塞

        synchronized (this) {
            // 尝试检索下一个Message
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
                // Stalled by a barrier.  Find the next asynchronous message in the queue.
                // msg.target为空的情况我不知道, do-while语句是寻找下一个可异步执行的Message
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                if (now < msg.when) {
                    // 下一个Message的可执行时间点未到, 这个Message有两种,一个是队头Message, 另一个是下一个可异步执行的Message
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 得到一个Message,如果是得到可异步执行的Message, prevMsg.next -> msg.next, return msg
                    // 如果是表头,将mMessage指向下一个Message, return msg
                    mBlocked = false;
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    return msg;
                }
            } else {
                // No more messages.
                nextPollTimeoutMillis = -1;
            }
            ...
        }
        ...
    }
}

无关(看不懂的)的代码我用省略号代替了,关键部分的代码的意思我写在注释中。到这里,MessageQueue如何去除Message的也已经讲解完了,说白了,就是一个队列的运用而已。最后,打起精神,咬下最后一根硬骨头,Message.recycleUnchecked()

void recycleUnchecked() {
    // Mark the message as in use while it remains in the recycled object pool.
    // Clear out all other details.
    flags = FLAG_IN_USE;
    what = 0;
    arg1 = 0;
    arg2 = 0;
    obj = null;
    replyTo = null;
    sendingUid = -1;
    when = 0;
    target = null;
    callback = null;
    data = null;

    synchronized (sPoolSync) {
        if (sPoolSize < MAX_POOL_SIZE) {
            next = sPool;
            sPool = this;
            sPoolSize++;
        }
    }
}

这个方法很简单,只是一些清空数据的代码而已,但是注意到一个静态变量没有——sPool,这是什么东西?它的变量声明也是一个Message对象,它是用来干什么的呢?解答疑惑的地方在Message的静态方法obtain里:

public static Message obtain() {
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            sPool = m.next;
            m.next = null;
            m.flags = 0; // clear in-use flag
            sPoolSize--;
            return m;
        }
    }
    return new Message();
}

不管是Handler.obtainMessage方法,还是Message另外几个obtain方法,最终都会通过调用Message.obtain()这个无参静态方法,它的代码也告诉了我们sPool的作用,它相当于指向一个栈的栈顶,每次使用后的Message实例都会压入这个栈中,每次使用或间接使用Message.obtain()方法都会从栈中弹出一个Message实例,以便做到循环使用,如果不这样子,这个栈就会无限增加Message实例,造成内存泄露,甚至内存溢出,这一点在开发的时候要注意。

最后我们总结一下研究成果:

Looper: 它是整个运作的场景,它在主线程中有唯一实例,它内部有唯一的消息队列,由它对整个运作进行初始化,并且调用loop()方法开始循环从消息队列中取消息,处理消息,回收消息。

MessageQueue: 它相当于一个队列容器,由它接收新的消息,在接收的时候会依照消息指定的处理时间点适当的插入到队列中,在取出的时候可能会因为下一个消息的时间点未到而阻塞。

Message: 它是一个消息,它由指定处理时间点、辅助处理的数据以及处理对象等元素组成。

Handler: 它是某个消息的消息处理者,它处理消息的方式有三种,但只能是其中之一处理,它们依次是Runnablerun()方法,Handler的内部类CallbackhandleMessage(Message)方法以及Handler的默认方法handleMessage(Message)

展开阅读全文
打赏
0
6 收藏
分享
加载中
更多评论
打赏
0 评论
6 收藏
0
分享
返回顶部
顶部