Android 線程間通訊原理

來源:互聯網
上載者:User

Android 線程間通訊原理

要理解原理, read the fucking source

1、從HandlerThread入手。

HandlerThread是android系統提供的類,繼承Thread,是一個線程。請看run方法。

     public void run() {        mTid = Process.myTid();        Looper.prepare();// #1        synchronized (this) {            mLooper = Looper.myLooper();// #2            notifyAll();        }        Process.setThreadPriority(mPriority);        onLooperPrepared();        Looper.loop();// #3        mTid = -1;    }
2、Thread和Looper的關係


在程式碼片段的第1個標示中,是調用了Looper的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));// #4    }

在程式碼片段的第4個標示中,將Looper執行個體存放線上程局部變數ThreadLocal中,將Looper和當前線程綁定。

在程式碼片段的第2個標示中,擷取了與當前線程綁定的Looper執行個體,當前線程就擁有了Looper執行個體。

在程式碼片段的第3個標示中,調用了Looper的loop()方法,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            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.recycle();        }    }


loop()方法的作用是:從Looper中擷取MessageQueue隊列,再從MessageQueue中取出Message,通過Handler發送出去,直到取完。或許有人會問,Message取完之後,在哪裡喚醒該線程,然後繼續迴圈擷取Message呢?沒錯,是在調用Handler的sendMessage後,向MessageQueue中插入訊息的時候喚醒,調用本地方法nativeWake(mPtr)。

3、Handler和Looper的關係

最常見的是,我們都會在Activity中建立一個Handler對象,用於更新UI介面。

   private Handler handler = new Handler(){        @Override        public void handleMessage(Message msg)        {            // TODO Auto-generated method stub            super.handleMessage(msg);        }    };


看看Handler的構造方法。

   public Handler() {        this(null, false);    }   public Handler(Callback callback, boolean async) {        if (FIND_POTENTIAL_LEAKS) {            final Class 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執行個體、Looper對象的MessageQueue隊列。

說到這裡,大家應該也差不多明白了他們究竟是怎麼樣的關係,線程間是如何交換訊息的了。Handler發送訊息的方法,其實就是往MessageQueue隊列中插入訊息。

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

而在調用了Handler的enqueueMessage方法時候會調用MessageQueue的enqueueMessage

final boolean enqueueMessage(Message msg, long when) {        if (msg.isInUse()) {            throw new AndroidRuntimeException(msg + " This message is already in use.");        }        if (msg.target == null) {            throw new AndroidRuntimeException("Message must have a target.");        }        boolean needWake;        synchronized (this) {            if (mQuiting) {                RuntimeException e = new RuntimeException(                        msg.target + " sending message to a Handler on a dead thread");                Log.w("MessageQueue", e.getMessage(), e);                return false;            }            msg.when = when;            Message p = mMessages;            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;            }        }        if (needWake) {            nativeWake(mPtr);// #5        }        return true;    }


在程式碼片段標示5中,調用了nativeWake(mPtr)方法,該方法是本地方法,用於喚醒Thread線程。

參考資料:

android的訊息佇列機制


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.