Handler,Looper&&在异步线程中更新UI

来源:互联网 发布:卸载软件怎么卸载 编辑:程序博客网 时间:2024/05/29 18:28
做过Android的同学一定非常熟悉Handler和Thread在Android中的重要性。我们一般会在一个线程中执行耗时操作然后通过Handler的post()或者sendMessage()的方法将消息发送出去(此时是在异步线程)。最后就会在handleMessage()根据what来执行相关的内容或者执行相应的Runnable(UI线程)。
那么这是如何执行的呢,为什么可以从非UI线程执行到了UI线程?这里面又接触到了两个类:MessageQueue和Looper。 
我们只需要看两个方法。
MessageQueue#enqueueMessage(Message msg,long when)
故名思义是将Message加入到队列中。加入的时候会通过synchronized防止同时修改,并且是根据when的时间顺序来加入的。
    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;    }
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();        }    }
则是在不断的从一个死循环中读取一个Message,然后通过dispatchMessage()去分发这个Message,最后会通过相应的handleMessage()或者Runnable去执行相应的事件。
至此就完成了从异步线程耗时操作到了UI线程的UI更新。可回想一下Android中关于异步线程中更新UI的方式。
1.Handler#sendMessage()
2.Handler#post()
3.View#post()
4.Activity#runOnUiThread()
这些方式的背后最终都是通过Handler,Looper的机制来实现的。
Handler解决了跨线程之间的通信。但是也存在一些确定,其中包括对消息的暂停,恢复等等。 


0 0