• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            羅朝輝(飄飄白云)

            關(guān)注嵌入式操作系統(tǒng),移動(dòng)平臺(tái),圖形開(kāi)發(fā)。-->加微博 ^_^

              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
              85 隨筆 :: 0 文章 :: 169 評(píng)論 :: 0 Trackbacks
            Android多線(xiàn)程分析之三:Handler,Looper的實(shí)現(xiàn)

            羅朝輝 (http://www.shnenglu.com/kesalin/)

            本文遵循“署名-非商業(yè)用途-保持一致”創(chuàng)作公用協(xié)議

            在前文《
            Android多線(xiàn)程分析之二:Thread的實(shí)現(xiàn)》中已經(jīng)詳細(xì)分析了Android Thread 是如何創(chuàng)建,運(yùn)行以及銷(xiāo)毀的,其重點(diǎn)是對(duì)相應(yīng) native 方法進(jìn)行分析,今天我將聚焦于 Android Framework 層多線(xiàn)程相關(guān)的類(lèi):Handler, Looper, MessageQueue, Message 以及它們與Thread 之間的關(guān)系??梢杂靡粋€(gè)不太妥當(dāng)?shù)谋扔鱽?lái)形容它們之間的關(guān)聯(lián):如果把 Thread 比作生產(chǎn)車(chē)間,那么 Looper 就是放在這車(chē)間里的生產(chǎn)線(xiàn),這條生產(chǎn)線(xiàn)源源不斷地從 MessageQueue 中獲取材料 Messsage,并分發(fā)處理 Message (由于Message 通常是完備的,所以 Looper 大多數(shù)情況下只是調(diào)度讓 Message 的 Handler 去處理 Message)。正是因?yàn)橄⑿枰?Looper 中處理,而 Looper 又需運(yùn)行在 Thread 中,所以不能隨隨便便在非 UI 線(xiàn)程中進(jìn)行 UI 操作。 UI 操作通常會(huì)通過(guò)投遞消息來(lái)實(shí)現(xiàn),只有往正確的 Looper 投遞消息才能得到處理,對(duì)于 UI 來(lái)說(shuō),這個(gè) Looper 一定是運(yùn)行在 UI 線(xiàn)程中。

            在編寫(xiě) app 的過(guò)程中,我們常常會(huì)這樣來(lái)使用 Handler:
            Handler mHandler = new Handler();
            mHandler.post(new Runnable(){
                @Override
                public void run() {
                    // do somework
                }
            });

            或者如這系列文章第一篇中的示例那樣: 
                private Handler mHandler= new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        Log.i("UI thread", " >> handleMessage()");

                        switch(msg.what){
                        case MSG_LOAD_SUCCESS:
                            Bitmap bitmap = (Bitmap) msg.obj;
                            mImageView.setImageBitmap(bitmap);

                            mProgressBar.setProgress(100);
                            mProgressBar.setMessage("Image downloading success!");
                            mProgressBar.dismiss();
                            break;

                        case MSG_LOAD_FAILURE:
                            mProgressBar.setMessage("Image downloading failure!");
                            mProgressBar.dismiss();
                            break;
                        }
                    }
                };

                Message msg = mHandler.obtainMessage(MSG_LOAD_FAILURE, null);
                mHandler.sendMessage(msg);

            那么,在 Handler 的 post/sendMessage 背后到底發(fā)生了什么事情呢?下面就來(lái)解開(kāi)這個(gè)謎團(tuán)。

            首先我們從 Handler 的構(gòu)造函數(shù)開(kāi)始分析:
                final MessageQueue mQueue; 
                final Looper mLooper; 
                final Callback mCallback; 
                final boolean mAsynchronous;

                public Handler(Looper looper, Callback callback, boolean async) {
                    mLooper = looper;
                    mQueue = looper.mQueue;
                    mCallback = callback;
                    mAsynchronous = async;
                }

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

                public Handler() {
                    this(nullfalse);
                }

            上面列出了 Handler 的一些成員變量:

            mLooper:線(xiàn)程的消息處理循環(huán),注意:并非每一個(gè)線(xiàn)程都有消息處理循環(huán),因此 Framework 中線(xiàn)程可以分為兩種:有 Looper 的和無(wú) Looper 的。為了方便 app 開(kāi)發(fā),F(xiàn)ramework 提供了一個(gè)有 Looper 的 Thread 實(shí)現(xiàn):HandlerThread。在前一篇《Thread的實(shí)現(xiàn)》中也提到了兩種不同 Thread 的 run() 方法的區(qū)別。
            /**
             * Handy class for starting a new thread that has a looper. The looper can then be 
             * used to create handler classes. Note that start() must still be called.
             
            */
            public class HandlerThread extends Thread {
                Looper mLooper;
                /**
                 * Call back method that can be explicitly overridden if needed to execute some
                 * setup before Looper loops.
                 
            */
                protected void onLooperPrepared() {
                }

                public void run() {
                    mTid = Process.myTid();
                    Looper.prepare();
                    synchronized (this) {
                        mLooper = Looper.myLooper();
                        notifyAll();
                    }
                    Process.setThreadPriority(mPriority);
                    onLooperPrepared();
                    Looper.loop();
                    mTid = -1;
                }

                /**
                 * This method returns the Looper associated with this thread. If this thread not been started
                 * or for any reason is isAlive() returns false, this method will return null. If this thread 
                 * has been started, this method will block until the looper has been initialized.  
                 * 
            @return The looper.
                 
            */
                public Looper getLooper() {
                    if (!isAlive()) {
                        return null;
                    }

                    // If the thread has been started, wait until the looper has been created.
                    synchronized (this) {
                        while (isAlive() && mLooper == null) {
                            try {
                                wait();
                            } catch (InterruptedException e) {
                            }
                        }
                    }
                    return mLooper;
                }
            }

            這個(gè) HandlerThread 與 Thread 相比,多了一個(gè)類(lèi)型為 Looper 成員變量 mLooper,它是在 run() 函數(shù)中由 Looper::prepare() 創(chuàng)建的,并保存在 TLS 中:
                 /** 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 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));
                }

            然后通過(guò) Looper::myLooper() 獲取創(chuàng)建的 Looper:
                /**
                 * Return the Looper object associated with the current thread.  Returns
                 * null if the calling thread is not associated with a Looper.
                 
            */
                public static Looper myLooper() {
                    return sThreadLocal.get();
                }

            最后通過(guò) Looper::Loop() 方法運(yùn)行消息處理循環(huán):從 MessageQueue 中取出消息,并分發(fā)處理該消息,不斷地循環(huán)這個(gè)過(guò)程。這個(gè)方法將在后面介紹。

            Handler 的成員變量 mQueue 是其成員變量 mLooper 的成員變量,這里只是為了簡(jiǎn)化書(shū)寫(xiě),單獨(dú)拿出來(lái)作為 Handler 的成員變量;成員變量 mCallback 提供了另一種使用Handler 的簡(jiǎn)便途徑:只需實(shí)現(xiàn)回調(diào)接口 Callback,而無(wú)需子類(lèi)化Handler,下面會(huì)講到的:
                /**
                 * Callback interface you can use when instantiating a Handler to avoid
                 * having to implement your own subclass of Handler.
                 
            */
                public interface Callback {
                    public boolean handleMessage(Message msg);
                }

            成員變量 mAsynchronous 是標(biāo)識(shí)是否異步處理消息,如果是的話(huà),通過(guò)該 Handler obtain 得到的消息都被強(qiáng)制設(shè)置為異步的。

            同是否有無(wú) Looper 來(lái)區(qū)分 Thread 一樣,Handler 的構(gòu)造函數(shù)也分為自帶 Looper 和外部 Looper 兩大類(lèi):如果提供了 Looper,在消息會(huì)在該 Looper 中處理,否則消息就會(huì)在當(dāng)前線(xiàn)程的 Looper 中處理,注意這里要確保當(dāng)前線(xiàn)程一定有 Looper。所有的 UI thread 都是有 Looper 的,因?yàn)?view/widget 的實(shí)現(xiàn)中大量使用了消息,需要 UI thread 提供 Looper 來(lái)處理,可以參考view.java:

            view.java

                public boolean post(Runnable action) {
                    final AttachInfo attachInfo = mAttachInfo;
                    if (attachInfo != null) {
                        return attachInfo.mHandler.post(action);
                    }
                    // Assume that post will succeed later
                    ViewRootImpl.getRunQueue().post(action);
                    return true;
                }

            ViewRootImpl.java

                private void performTraversals() {
                    .
                    // Execute enqueued actions on every traversal in case a detached view enqueued an action
                    getRunQueue().executeActions(attachInfo.mHandler);
                  
                }

                static RunQueue getRunQueue() {
                    RunQueue rq = sRunQueues.get();
                    if (rq != null) {
                        return rq;
                    }
                    rq = new RunQueue();
                    sRunQueues.set(rq);
                    return rq;
                }

                /**
                 * The run queue is used to enqueue pending work from Views when no Handler is
                 * attached.  The work is executed during the next call to performTraversals on
                 * the thread.
                 * @hide
                 
            */
                static final class RunQueue {
                
                    void executeActions(Handler handler) {
                        synchronized (mActions) {
                            final ArrayList<HandlerAction> actions = mActions;
                            final int count = actions.size();

                            for (int i = 0; i < count; i++) {
                                final HandlerAction handlerAction = actions.get(i);
                                handler.postDelayed(handlerAction.action, handlerAction.delay);
                            }

                            actions.clear();
                        }
                    }
                }

            從上面的代碼可以看出,作為所有控件基類(lèi)的 view 提供了 post 方法,用于向 UI Thread 發(fā)送消息,并在 UI Thread 的 Looper 中處理這些消息,而 UI Thread  一定有 Looper 這是由 ActivityThread 來(lái)保證的:
            public final class ActivityThread {

                final Looper mLooper = Looper.myLooper();
            }

            UI 操作需要向 UI 線(xiàn)程發(fā)送消息并在其 Looper 中處理這些消息。這就是為什么我們不能在非 UI 線(xiàn)程中更新 UI 的原因,在控件在非 UI 線(xiàn)程中構(gòu)造 Handler 時(shí),要么由于非 UI 線(xiàn)程沒(méi)有 Looper 使得獲取 myLooper 失敗而拋出 RunTimeException,要么即便提供了 Looper,但這個(gè) Looper 并非 UI 線(xiàn)程的 Looper 而不能處理控件消息。為此在 ViewRootImpl 中有一個(gè)強(qiáng)制檢測(cè) UI 操作是否是在 UI 線(xiàn)程中處理的方法 checkThread():該方法中的 mThread 是在 ViewRootImpl 的構(gòu)造函數(shù)中賦值的,它就是 UI 線(xiàn)程;該方法中的 Thread.currentThread() 是當(dāng)前進(jìn)行 UI 操作的線(xiàn)程,如果這個(gè)線(xiàn)程不是非 UI 線(xiàn)程就會(huì)拋出異常CalledFromWrongThreadException。
                void checkThread() {
                    if (mThread != Thread.currentThread()) {
                        throw new CalledFromWrongThreadException(
                                "Only the original thread that created a view hierarchy can touch its views.");
                    }
                }

            如果修改《使用Thread異步下載圖像》中示例,下載完圖像 bitmap 之后,在 Thread 的 run() 函數(shù)中設(shè)置 ImageView 的圖像為該 bitmap,即會(huì)拋出上面提到的異常:
            W/dalvikvm(796): threadid=11: thread exiting with uncaught exception (group=0x40a71930)
            E/AndroidRuntime(796): FATAL EXCEPTION: Thread-75
            E/AndroidRuntime(796): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
            E/AndroidRuntime(796):     at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:4746)
            E/AndroidRuntime(796):     at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:823)
            E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
            E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
            E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
            E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
            E/AndroidRuntime(796):     at android.view.View.requestLayout(View.java:15473)
            E/AndroidRuntime(796):     at android.widget.ImageView.setImageDrawable(ImageView.java:406)
            E/AndroidRuntime(796):     at android.widget.ImageView.setImageBitmap(ImageView.java:421)
            E/AndroidRuntime(796):     at com.example.thread01.MainActivity$2$1.run(MainActivity.java:80)

            Handler 的構(gòu)造函數(shù)暫且介紹到這里,接下來(lái)介紹:handleMessage 和 dispatchMessage:
                /**
                 * Subclasses must implement this to receive messages.
                 
            */
                public void handleMessage(Message 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);
                    }
                }

            前面提到有兩種方式來(lái)設(shè)置處理消息的代碼:一種是設(shè)置 Callback 回調(diào),一種是子類(lèi)化 Handler。而子類(lèi)化 Handler 其子類(lèi)就要實(shí)現(xiàn) handleMessage 來(lái)處理自定義的消息,如前面的匿名子類(lèi)示例一樣。dispatchMessage 是在 Looper::Loop() 中被調(diào)用,即它是在線(xiàn)程的消息處理循環(huán)中被調(diào)用,這樣就能讓 Handler 不斷地處理各種消息。在 dispatchMessage 的實(shí)現(xiàn)中可以看到,如果 Message 有自己的消息處理回調(diào),那么就優(yōu)先調(diào)用消息自己的消息處理回調(diào):
                private static void handleCallback(Message message) {
                    message.callback.run();
                }

            否則看Handler 是否有消息處理回調(diào) mCallback,如果有且 mCallback 成功處理了這個(gè)消息就返回了,否則就調(diào)用 handleMessage(通常是子類(lèi)的實(shí)現(xiàn)) 來(lái)處理消息。

            在分析 Looper::Loop() 這個(gè)關(guān)鍵函數(shù)之前,先來(lái)理一理 Thread,Looper,Handler,MessageQueue 的關(guān)系:Thread 需要有 Looper 才能處理消息(也就是說(shuō) Looper 是運(yùn)行在 Thread 中),這是通過(guò)在自定義 Thread 的 run() 函數(shù)中調(diào)用 Looper::prepare() 和 Looper::loop() 來(lái)實(shí)現(xiàn),然后在 Looper::loop() 中不斷地從 MessageQueue 獲取由 Handler 投遞到其中的 Message,并調(diào)用 Message 的成員變量 Handler 的 dispatchMessage 來(lái)處理消息。

            下面先來(lái)看看 Looper 的構(gòu)造函數(shù):
                final MessageQueue mQueue;
                final Thread mThread;
                volatile boolean mRun;

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

            Looper 的構(gòu)造函數(shù)很簡(jiǎn)單,創(chuàng)建MessageQueue,保存當(dāng)前線(xiàn)程到 mThread 中。但它是私有的,只能通過(guò)兩個(gè)靜態(tài)函數(shù) prepare()/prepareMainLooper() 來(lái)調(diào)用,前面已經(jīng)介紹了 prepare(),下面來(lái)介紹 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 是通過(guò)調(diào)用 prepare 實(shí)現(xiàn)的,不過(guò)傳入的參數(shù)為 false,表示 main Looper 不允許中途被中止,創(chuàng)建之后將looper 保持在靜態(tài)變量 sMainLooper 中。整個(gè) Framework 框架只有兩個(gè)地方調(diào)用了 prepareMainLooper 方法:

            第一處是在 SystemServer.java 中的 ServerThread,ServerThread 的重要性就不用說(shuō)了,絕大部分 Android Service 都是這個(gè)線(xiàn)程中初始化的。這個(gè)線(xiàn)程是在 Android 啟動(dòng)過(guò)程中的 init2() 方法啟動(dòng)的:
                public static final void init2() {
                    Slog.i(TAG, "Entered the Android system server!");
                    Thread thr = new ServerThread();
                    thr.setName("android.server.ServerThread");
                    thr.start();
                }
            class ServerThread extends Thread {
                @Override
                public void run() {
                    
                    Looper.prepareMainLooper();
                    
                    Looper.loop();
                    Slog.d(TAG, "System ServerThread is exiting!");
                }
            }

            第二處是在 ActivityThread.java 的 main() 方法中:
                public static void main(String[] args) {
                    .
                    Looper.prepareMainLooper();

                    ActivityThread thread = new ActivityThread();
                    thread.attach(false);

                    if (sMainThreadHandler == null) {
                        sMainThreadHandler = thread.getHandler();
                    }

                    AsyncTask.init();

                    Looper.loop();

                    throw new RuntimeException("Main thread loop unexpectedly exited");
                }

            ActivityThread 的重要性也不言而喻,它是 Activity 的主線(xiàn)程,也就是 UI 線(xiàn)程。注意這里的 AsyncTask.init() ,在后面介紹 AsyncTask 時(shí)會(huì)詳細(xì)介紹的,這里只提一下:AsyncTask 能夠進(jìn)行 UI 操作正是由于在這里調(diào)用了 init()。

            有了前面的鋪墊,這下我們就可以來(lái)分析 Looper::Loop() 這個(gè)關(guān)鍵函數(shù)了:
               /**
                 * 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;
                    
                    for (;;) {
                        Message msg = queue.next(); // might block
                        if (msg == null) {
                            // No message indicates that the message queue is quitting.
                            return;
                        }

                        msg.target.dispatchMessage(msg);

                        msg.recycle();
                    }
                }

            loop() 的實(shí)現(xiàn)非常簡(jiǎn)單,一如前面一再說(shuō)過(guò)的那樣:不斷地從 MessageQueue 中獲取消息,分發(fā)消息,回收消息。從上面的代碼可以看出,loop() 僅僅是一個(gè)不斷循環(huán)作業(yè)的生產(chǎn)流水線(xiàn),而 MessageQueue 則為它提供原材料 Message,讓它去分發(fā)處理。至于 Handler 是怎么提交消息到 MessageQueue 中,MessageQueue 又是怎么管理消息的,且待下文分解。
            posted on 2014-07-12 11:00 羅朝輝 閱讀(2966) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): 移動(dòng)開(kāi)發(fā)
            久久影院综合精品| 国产无套内射久久久国产| 狠狠色噜噜色狠狠狠综合久久| 久久久国产精华液| 久久亚洲精品人成综合网| 91精品国产9l久久久久| 999久久久免费国产精品播放| 久久久WWW成人| 久久毛片一区二区| 久久精品国产91久久麻豆自制| 国产精品久久久久久久久久免费| 伊人久久一区二区三区无码| 无码超乳爆乳中文字幕久久 | 青草影院天堂男人久久| 久久99精品九九九久久婷婷| 久久久久久久波多野结衣高潮| 久久婷婷五月综合国产尤物app | 99精品国产免费久久久久久下载| 国内精品久久久久伊人av| 久久99精品免费一区二区| 精产国品久久一二三产区区别| 国产精品久久精品| 久久综合九色综合网站| 久久精品国产精品青草app| 亚洲一区精品伊人久久伊人| 久久99精品国产| 伊人久久大香线蕉av不卡| 久久久久久国产a免费观看不卡| 欧美午夜精品久久久久免费视 | 精品无码久久久久久尤物| 久久这里有精品视频| 久久精品国产91久久综合麻豆自制| 一级做a爰片久久毛片看看| 91久久精品国产成人久久| 久久综合狠狠综合久久综合88| 亚洲国产小视频精品久久久三级 | 色88久久久久高潮综合影院| 国内精品久久久久久麻豆| 久久九九精品99国产精品| 久久久久人妻一区二区三区| 人妻丰满?V无码久久不卡|