Android Handler如何实现线程间通信,源码分析。

来源:互联网 发布:python培训班 编辑:程序博客网 时间:2024/05/17 22:43

源码分析Android Handler是如何实现线程间通信的

Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的。开发者从一开始就被告知必须在主线程中进行UI操作。但Handler是如何实现线程间通信的呢?本文将从源码中分析Handler的消息通信机制。

0x00 Handler使用

首先看看我们平时是如何使用的Handler的。先看看以下代码

//定义HandlerHandler mHandler = new Handler(){  public void handleMessage(Message msg){    switch(msg.what){      case UPDATE_UI:        updateUI(msg);        break;    }  }};class MyThread extends Thread{  public void run(){    //do same work!    ...    //send message    Message msg = mHandler.obtainMessage(UPDATE_UI);    mHandler.sendMessage(msg);  }}private void updateUI(Message msg){  //update UI}

在子线程中sendMessage(Message)发送消息,然后在Handler的handleMessage(Message)接收消息,执行更新UI操作。那么Handler是如何把消息从MyThread传递到MainThread中来呢?我们从sendMessage()开始慢慢揭开它的面纱。

0x01 sendMessage(Message)

public final boolean sendMessage(Message msg){    return sendMessageDelayed(msg, 0);}...public final boolean sendMessageDelayed(Message msg, long delayMillis){    if (delayMillis < 0) {      delayMillis = 0;    }    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);}...public boolean sendMessageAtTime(Message msg, long uptimeMillis) {    MessageQueue queue = mQueue;    if (queue == null) {        RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");        Log.w("Looper", e.getMessage(), e);        return false;    }    return enqueueMessage(queue, msg, uptimeMillis);}...private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {    msg.target = this;    if (mAsynchronous) {        msg.setAsynchronous(true);    }    return queue.enqueueMessage(msg, uptimeMillis);}

我们发现调用sendMessage()方法最后都走到enqueueMessage()这个方法,一开始就把当前Handler实例赋给了Message.target的属性里面,后面可以知道这个target是用来执行处理函数回调的。

enqueueMessage方法是把Message信息放入到一个MessageQueue的队列中。顾名思义MessageQueue就是消息队列。从sendMessageAtTime()方法知道这个MessageQueueHandler中的一个成员。它是在Handler的构造函数中通过Loopger对象来初始化的。

0x02 Handler构造函数

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

这时候我们脑海知道创建Handler的时候,同时也创建了Looper实例和MessageQueue引用(MessageQueue对象其实是在Looper中构造的)。Looper是何物呢?简单地说就是消息循环,这个我们稍后会分析。

0x03 enqueueMessage(MessageQueue)

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

MessageQueue中可以看到这个入列方法中有一个for循环就是把当前的需要处理Message放到队列的合适位置。因为需要处理的Message对象都有一个开始处理的时间when,这个队列是按照when排序的。

至此,Handler调用sendMessage()方法后就把Message消息通过enqueueMessage()插入MessageQueue队列中。

而这个MessageQueue是在Looper中维护的。

0x04 prepare()创建Looper

0x02中我们知道创建Handler时就使用静态方法Looper.myLooper()得到当前线程的Looper对象。

/** * Return the Looper object associated with the current thread.  Returns * null if the calling thread is not associated with a Looper. */public static @Nullable Looper myLooper() {    return sThreadLocal.get();}

sThreadLocal是一个ThreadLocal类型的静态变量。什么时候会把Looper对象放在sThreadLocal中呢?通过prepare()方法。

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在构造函数中创建MessageQueue对象

private Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);    mThread = Thread.currentThread();}

调用prepare()方法将一个Looper对象放在了静态的ThreadLocal对象中。这个是一个与线程绑定的对象,且在内存中仅保存了一份引用。

使用ThreadLocal对象这一点非常巧妙,也非常重要,这是线程间通信的基础。即在线程中调用prepare()时就在该线程中绑定了Looper对象,而Looper对象中拥有MessageQueue引用。所以每个线程都有一个消息队列

这样HandlerLooperMessageQueue这几个类关系大概就可以画出来了。

0x05 启动循环loop()

/** * Run the message queue in this thread. Be sure to call * {@link #quit()} to end the 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        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();    }}

loop()方法中有一个无限循环,不停地读取调用MessageQueuenext()方法。当next()没有返回时就阻塞在这里。当获取到MessageQueue中的消息时,就执行了处理消息的回调函数msg.target.dispatchMessage(msg)

前面0x01分析我们知道msg.target是在Handler中的enqueueMessage()进行赋值,即它指向当前的Handler实例。

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

执行msg.target.dispatchMessage(msg)后便走到了以下流程

/** * Handle system messages here. */public void dispatchMessage(Message msg) {    if (msg.callback != null) {        handleCallback(msg);    } else {        if (mCallback != null) {            if (mCallback.handleMessage(msg)) {                return;            }        }        handleMessage(msg);    }}

这里就是回调handleMessage(msg)函数处理消息的地方。Handler负责将Message入列,Looper则负责循环从MessageQueue中取出需要处理的Message并交由Handler来处理。

0x06 启动主线程的消息循环

我们知道通过静态方法Looper.prepare()创建了绑定当前线程的Looper对象,而通过loop()启动一个循环不停地读取队列中Message。但是Android系统是什么时候启动了主线程的消息循环呢?

要理解这一点就必须进入Android应用程序的入口ActivityThreadmain方法。

public static void main(String[] args) {    ...    Looper.prepareMainLooper();    ...    Looper.loop();    throw new RuntimeException("Main thread loop unexpectedly exited");}

可以看出main方法中先后执行了Looper.prepareMainLooper()方法和Looper.loop()方法。正常情况下main方法不会退出,只有loop()方法发生异常后将会抛出RuntimeException

0x07 Looper.prepareMainLooper()

/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself.  See also: {@link #prepare()} */public static void prepareMainLooper() {    prepare(false);    synchronized (Looper.class) {        if (sMainLooper != null) {            throw new IllegalStateException("The main Looper has already been prepared.");        }        sMainLooper = myLooper();    }}

prepareMainLooper()方法其实是调用了prepare()方法。

当我们启动应用时系统就调用了prepareMainLooper()并在主线程中绑定了一个Looper对象。

这时候我们回过来看看一开始的Handler使用方式。在主线程中我们创建了Handler对象,在Handler构造函数中初始化了Looper(即获取到了绑定在主线程中的Looper对象)。当在子线程MyThread中通过mHandler.sendMessage(msg)方法发送一个消息时就把Message放在与主线程绑定的MessageQueue中。这样在子线程中使用Handler就实现了消息的通信。

可以简单的使用以下类图表示,每个线程都由一个Handler,每个Handler都是与当前所在线程的Looper绑定

0x08 主线程是否会阻塞

0x06中知道在ActivityTheadmain方法中启动了一个死循环。那主线程是不是就一直阻塞在这里呢?其实不然。可以看到ActivityThread类里面有一个自定义的Handler对象mH,在这里对象中handleMessage()回调中定义了Activity的各种交互如管理Activity生命周期,启动service,显示window等,都是通过Handler进行处理的。同时可以看出只有当应用退出EXIT_APPLICATION之后才回调用Looper.quit()停止消息循环。

public void handleMessage(Message msg) {    ...    switch (msg.what) {        case LAUNCH_ACTIVITY: {            ...            handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        } break;        ...        case PAUSE_ACTIVITY: {            ...            handlePauseActivity((IBinder) args.arg1, false,                    (args.argi1 & USER_LEAVING) != 0, args.argi2,                    (args.argi1 & DONT_REPORT) != 0, args.argi3);            ...        } break;        ...        case SHOW_WINDOW:            ...            handleWindowVisibility((IBinder)msg.obj, true);            ...            break;        ...        case EXIT_APPLICATION:            if (mInitialApplication != null) {                mInitialApplication.onTerminate();            }            Looper.myLooper().quit();            break;        ...    }    ...}

0x09 总结

当创建Handler时将通过ThreadLocal在当前线程绑定一个Looper对象,而Looper持有MessageQueue对象。执行Handler.sendMessage(Message)方法将一个待处理的Message插入到MessageQueue中,这时候通过Looper.loop()方法获取到队列中Message,然后再交由Handler.handleMessage(Message)来处理。

0 0