Handler,Looper,Message,MessageQueue之間關係淺析,loopermessagequeue

來源:互聯網
上載者:User

Handler,Looper,Message,MessageQueue之間關係淺析,loopermessagequeue
一、先看一下使用流程

1.在子線程中使用Handler執行個體

    /***********子線程使用Handler執行個體*********/    private class LooperThread extends Thread    {        public Handler handler;        @Override        public void run()        {            Looper.prepare();            handler = new Handler()            {                @Override                public void handleMessage(Message msg)                {                        }            };            Looper.loop();        }    }

2、主線程(UI線程)中使用的Handler,Looper等其實現在android/app/AcitvityThread.java檔案中,如下:

public static void main(String[] args) {        //前面一系列配置暫時不用關心        SamplingProfilerIntegration.start();        CloseGuard.setEnabled(false);        Environment.initForCurrentUser();        EventLogger.setReporter(new EventLoggingReporter());        Security.addProvider(new AndroidKeyStoreProvider());        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());        TrustedCertificateStore.setDefaultUserDirectory(configDir);        Process.setArgV0("<pre-initialized>");        /************從這裡開始,使用Looper*******************/        Looper.prepareMainLooper();//對比:子線程中使用Looper.prepare();         ActivityThread thread = new ActivityThread();        thread.attach(false);         if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();//對比:子線程中自建立new Handler()        }         if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }         Looper.loop();//對比:這裡兩者相同         throw new RuntimeException("Main thread loop unexpectedly exited");    }

二、查看源碼:(一)prepare()1、看一下Looper.prepare()的源碼:
    /** 將當前線程初始化為一個Looper.所以你可以在start loop前先建立Handlers,再引用這個looper;      * 要確保在調用本方法後調用#loop()方法;結束本方法使用#quit();      */    public static void prepare() {        prepare(true);         //對比:下面將會看到主線程中的prepareMainLooper中將會使用prepare(false)    }     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));    }
附I)這裡引出了一個sThreadLocal,首先看其定義:

    // sThreadLocal.get() will return null unless you've called prepare().    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    ThreadLocal類是個特殊的全域變數,其全域性只體現在自己的所在的線程(類名也體現出該特性),故因此每個線程的Looper都是獨立的;    ThreadLocal類Java本身已經給予實現,Android對其進行了實現最佳化;其主要思想仍為:ThreadLocal是如何做到為每一個線程維護變數的副本的呢?其實實現的思路很簡單,在ThreadLocal類中有一個Map,用於儲存每一個線程的變數的副本,Map中元素的鍵為線程對象,而值對應線程的變數副本。
    前面源碼中涉及到的get(),set(0方法分別為擷取和設定當前線程所對應的線程局部變數值。
2、對比看一下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) {                thrownew IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }       /**     * 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();    }
附II): sMainLooper的定義:

    private static Looper sMainLooper;

和前面大致相同,只是定義了一個sMainLooper,get sThreadLocal獲得一個Looper,讓sMainLooper指向它;

(二)Handler

1、Handler部分源碼:

Handler眾多建構函式:

    public Handler() {        this(null, false);    }    public Handler(Callback callback) {        this(callback, false);    }     public Handler(Looper looper) {        this(looper, null, false);    }     public Handler(Looper looper, Callback callback) {        this(looper, callback, false);    }     public Handler(boolean async) {        this(null, async);    }     public Handler(Looper looper, Callback callback, boolean async) {        mLooper = looper;        mQueue = looper.mQueue;        mCallback = callback;        mAsynchronous = async;    }   /****************重點看此建構函式*********************/    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();//依然通過sThreadLocal擷取到當前Thread的Looper執行個體,可見這裡兩者聯絡到一起        if (mLooper == null) {            throw new RuntimeException(                "Can't create handler inside thread that has not called Looper.prepare()");        }        mQueue = mLooper.mQueue;   //這裡MessageQueue是Looper與Handler溝通的橋樑        mCallback = callback;        mAsynchronous = async;    }
附I)mQueue的定義:final MessageQueue mQueue;

可見通過MessageQueue,Handler與Looper聯絡到一起;

(三)Looper.loop()處理事件流程

    public static void loop() {        final Looper me = myLooper();//依然通過sThreadLocal擷取到當前Thread的Looper執行個體        if (me == null) {            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");        }        final MessageQueue queue = me.mQueue;//擷取到上面提到過的MessageQueue mQueue        Binder.clearCallingIdentity();        final long ident = Binder.clearCallingIdentity();        /****************迴圈處理訊息*******************/        for (;;) {            Message msg = queue.next(); // 從MessageQueue中取出next訊息            if (msg == null) {                // No message indicates that the message queue is quitting.                //表明當前MessageQueue正在退出                return;            }             // 調試資訊,跳過            Printer logging = me.mLogging;            if (logging != null) {                logging.println(">>>>> Dispatching to " + msg.target + " " +                        msg.callback + ": " + msg.what);            }            /** 開始指派訊息*/            msg.target.dispatchMessage(msg);//Message中的定義Handler target,故dispatchMessage                                            //最終調用Handler中的處理函數;             /** 調試資訊,跳過*/            if (logging != null) {                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);            }            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        }    }
再看一下Looper的建構函式:
    private Looper(boolean quitAllowed) {          //建構函式是private的            mQueue = new MessageQueue(quitAllowed);//MessageQueue是Looper建立時就被建立出來的            mThread = Thread.currentThread();      //mThread為當前線程,即Looper與當前線程建立聯絡    }
由上loop()方法可以簡單得出結論,Looper用以處理MessageQueue中的取出的Message,由MessageQueue是Handler及Looper所共用的,取出的Message則交由Handler進行處理。而Handler也能夠通過post或者send等方式將Message添加到MessageQueue中供Looper後續進行取出處理。sThreadLocal保證了Looper是線程私人的,所有資訊發送與處理都是在本線程中。

    prepare()用以在sThreadLocal中建立線程與該線程對應的Looper的鍵值對;new Handler或者getHandler建立的Handler都根據sThreadLocal.get()進行擷取;建立的Handler與Looper共用MessageQueue;loop開始迴圈處理Messagequeue中的事件。其即為整個流程。

聯繫我們

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