Android Handler、Looper、MessageQueue以及Message源码分析

来源:互联网 发布:套装软件 编辑:程序博客网 时间:2024/05/18 00:37

一、APP应用程序入口

APP应用程序入口为ActivityThread类中的main方法(主线程)。主要代码如下:

    public static void main(String[] args) {        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");        SamplingProfilerIntegration.start();        Process.setArgV0("<pre-initialized>");        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

其中可以看到初始化UI主线程的Looper对象,通过Looper.prepareMainLooper()方法,在本方法中,调用了,prepare(boolean quitAllowed),该标识会传递给其对应的消息队列MessageQueue,通过代码可以看出,UI主线程对应的消息循环队列是不允许退出的。quitAllowed默认传入了false- prepare(false);
如下:

   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));    }    //Looper构造器    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }

二、Handler

Handler的构造方法可以分为2类:
(1)传入指定线程looper对象;
(2)不传入looper对象,默认为UI主线程的looper对象。

1)传入指定线程looper对象的构造方法    public Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;        mAsynchronous = async;    }(2)不传入looper对象,默认为UI主线程的looper对象。public Handler(Callback callback, boolean async) {        ...        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;    }

在Handler初始化时,会初始化一个Looper对象和Looper中对应的消息队列mLooper.mQueue对象。
mAsynchronous 的作用:为True时,发送消息为异步消息。

如下为Handler中的消息分发方法dispatchMessage。也就是如果在初始化Handler时,传入Callback,优先将消息传递给Callback,否则,传递给大家最为熟悉的Handler的handleMessage(msg)方法。

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

Handler初始化后,接着去看看Looper中的实现。

二、Looper

(1)Looper初始化

Looper对外提供了两个静态的公共方法
其中在工作线程调用Looper.prepare()方法,其对应的MessageQueue消息队列是可以退出的。

源代码如下:

//(1) prepare()用于在工作线程中调用    public static void prepare() {        prepare(true);    }    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));    }//(2)prepareMainLooper()用于在UI主线程中调用    public static void prepareMainLooper() {        prepare(false);        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }    //Looper构造器    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mThread = Thread.currentThread();    }

(2)Looper的loop()方法

从源码中可以看出,loop()方法中通过死循环for,将消息队列MessageQueue中的消息取出,然后调用
msg.target.dispatchMessage(msg);方法将消息分发传递到Handler的dispatchMessage方法。
从而可以在Handler的callback或者handleMessage()中处理改消息。
在loop()方法的最后,调用了msg.recycleUnchecked();处理完的消息msg,会被置空初始化,并加入到消息缓冲池中。Message中缓冲池的最大为50。

   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            final Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }            final long traceTag = me.mTraceTag;            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));            }            try {                msg.target.dispatchMessage(msg);            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }            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();        }    }//消息缓冲池的最大容量为50private static final int MAX_POOL_SIZE = 50;//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++;            }        }    }

三、MessageQueue

1. enqueueMessage(Message msg, long when)方法 —— Handler中发送消息的方法最终都是调用消息队列中的该方法,把消息加入到消息队列中。

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

2 . Message next() {}方法,返回一个msg,该方法是上面提到的在Looper中的loop()方法中调用。

3. IdleHander内部接口——可通过addIdleHandler/removeIdleHandler方法,添加或移除回调。

如果消息队列没有消息,也就是在UI主线程或者工作线程空闲时候,会循环调用mIdleHandlers集合中的IdleHander对象,执行queueIdle()方法。如果queueIdle()返回false,则就会从改集合中移除,也就是只执行一次。适合做延迟加载。

Message next() {        // Return here if the message loop has already quit and been disposed.        // This can happen if the application tries to restart a looper after quit        // which is not supported.        final long ptr = mPtr;        if (ptr == 0) {            return null;        }        int pendingIdleHandlerCount = -1; // -1 only during first iteration        int nextPollTimeoutMillis = 0;        for (;;) {            if (nextPollTimeoutMillis != 0) {                Binder.flushPendingCommands();            }            nativePollOnce(ptr, nextPollTimeoutMillis);            synchronized (this) {                // Try to retrieve the next message.  Return if found.                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.                    do {                        prevMsg = msg;                        msg = msg.next;                    } while (msg != null && !msg.isAsynchronous());                }                if (msg != null) {                    if (now < msg.when) {                        // Next message is not ready.  Set a timeout to wake up when it is ready.                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);                    } else {                        // Got a message.                        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;                }                // Process the quit message now that all pending messages have been handled.                if (mQuitting) {                    dispose();                    return null;                }                // If first time idle, then get the number of idlers to run.                // Idle handles only run if the queue is empty or if the first message                // in the queue (possibly a barrier) is due to be handled in the future.                if (pendingIdleHandlerCount < 0                        && (mMessages == null || now < mMessages.when)) {                    pendingIdleHandlerCount = mIdleHandlers.size();                }                if (pendingIdleHandlerCount <= 0) {                    // No idle handlers to run.  Loop and wait some more.                    mBlocked = true;                    continue;                }                if (mPendingIdleHandlers == null) {                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];                }                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);            }            // Run the idle handlers.            // We only ever reach this code block during the first iteration.            for (int i = 0; i < pendingIdleHandlerCount; i++) {                final IdleHandler idler = mPendingIdleHandlers[i];                mPendingIdleHandlers[i] = null; // release the reference to the handler                boolean keep = false;                try {                    keep = idler.queueIdle();                } catch (Throwable t) {                    Log.wtf(TAG, "IdleHandler threw exception", t);                }                if (!keep) {                    synchronized (this) {                        mIdleHandlers.remove(idler);                    }                }            }            // Reset the idle handler count to 0 so we do not run them again.            pendingIdleHandlerCount = 0;            // While calling an idle handler, a new message could have been delivered            // so go back and look again for a pending message without waiting.            nextPollTimeoutMillis = 0;        }    }

四、Message

1. 创建Handler发送所需的消息Msg——通过Message.obtain()以及重载方法

在Message中定义了消息缓存的最大容量MAX_POOL_SIZE 为50。sPool的赋值是通过recycleUnchecked()方法中。之前提到过该方法是在Looper.loop方法的最后才调用。也就是处理完第一个消息的时候,就开始把消息加入到sPool这个缓存对象的next中。下次调用msg.obtain()方法就会从缓存中取出。

private static Message sPool;private static final int MAX_POOL_SIZE = 50; /**     * Return a new Message instance from the global pool. Allows us to     * avoid allocating new objects in many cases.     */    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();    }    /**     * Recycles a Message that may be in-use.     * Used internally by the MessageQueue and Looper when disposing of queued Messages.     */    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++;            }        }    }

至此对Handler、Looper、MessageQueue和Message的部分源码分析完毕。

收获要点总结:

  1. App程序入口——ActivityThread中main()方法,并对UI主线程的Looper进行初始化。
  2. Handler创建——Handler初始化不指定Looper对象默认为UI主线程对应的Looper,消息发送底层是通过Looper对象中的mQueue对象,把消息加入到消息队列。通过loop()方法循环取出处理。
  3. Looper——UI主线程的消息队列是不允许停止退出的。Looper.prepare()方法调用会和所在线程进行绑定,保存到ThreadLocal中。一一对应的关系。
  4. MessageQueue——消息队列中有next()方法取出消息和enqueueMessage()方法把消息加入到队列中。还有一个重要的内部接口IdleHandler,在消息队列消息为空时执行。
  5. Message——消息,内部做了缓冲的机制,缓冲容量为50。
阅读全文
0 0
原创粉丝点击