Android基礎篇之Handler實現原理

來源:互聯網
上載者:User

 當啟動一個apk應用程式的時候,Android會開啟一個主線程(UI線程),由於主線程是非安全執行緒,當我們需要在主線程中操作大資料或者連網等這些耗時的操作時,會影響到Android UI的顯示並且會出現假死狀態,這對使用者的體驗來說是很不樂觀的。因此,我們需要把那些耗時的操作交給另外一個線程來處理,子線程將處理的結果返回給主線程,主線程根據得到的資料作出相應的操作。Handler就實現了這一機制。在Android中實現訊息處理的主要有:Handler、Message、Looper、MessageQueue這幾個類。我們來看看這幾個類內部到底是怎麼運轉的。

 

 Looper.prepare初始化當前線程,看看都初始化了一些什麼。

public class Looper {    private static final String TAG = "Looper";       static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();//線程TLS    private static Looper sMainLooper;     final MessageQueue mQueue;//訊息佇列    final Thread mThread;//當前線程    volatile boolean mRun;    private Printer mLogging;     /** Initialize the current thread as a looper.      * This gives you a chance to create handlers that then reference      * this looper, before actually starting the loop. Be sure to call      * {@link #loop()} after calling this method, and end it by calling      * {@link #quit()}.      */    public static void prepare() {        prepare(true);    }    private Looper(boolean quitAllowed) {        mQueue = new MessageQueue(quitAllowed);        mRun = true;        mThread = Thread.currentThread();    }    private static void prepare(boolean quitAllowed) {        if (sThreadLocal.get() != null) {//當前線程如果已經有Looper的時候則建立失敗,由此可見,一個線程只能有一個Looper            throw new RuntimeException("Only one Looper may be created per thread");        }//建立Looper對象並儲存到當前線程的TLS        sThreadLocal.set(new Looper(quitAllowed));    }}

 

就這樣Looper的初始工作已經完成了,然後就是迴圈監聽訊息。

    public static void loop() {        final Looper me = myLooper();//擷取當前線程的Looper        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        final MessageQueue queue = me.mQueue;//擷取當前線程的訊息佇列                Binder.clearCallingIdentity();        final long ident = Binder.clearCallingIdentity();//這裡就是開始迴圈的地方,這是一個死迴圈,我記得2.x的版本是while(true),也許是考慮效率問題嘛。for(;;)效率要高些        for (;;) {            Message msg = queue.next(); //擷取訊息            if (msg == null) {                // No message indicates that the message queue is quitting.                return;            }            Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }//這裡就是把訊息交給handler來處理。由於一個線程可能有多個Handler對象發送訊息(Message)。//所以,每個Message對象儲存了自己的Handler。這樣Looper才知道到底要交給哪一個Handler來處理。            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);            }//釋放message資源            msg.recycle();        }    }

接下看,在看看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());            }        }//在這裡擷取當前線程的Looper        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.sendMessage發送資料,最終使用的時enqueueMessage方法

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {//設定message的target為當前Handler//與在Looper.loop() 裡面的 msg.target.dispatchMessage(msg) 相對應        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

 

Handler.dispatchMessage接收資料

 public void dispatchMessage(Message msg) {//msg.calllbak 是一個Runable,如果不為空白就執行run方法來處理這個message        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }//否則調用我們自己現實handler的回呼函數            handleMessage(msg);        }    }

 整個訊息的處理就到這裡了,一些細節的方面就在以後的項目中再來慢慢體會。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.