【Android個人理解(一)】通過Looper與Handle的關係,理解Looper工作機制

Looper與Handle是Android獨有的新概念,但我們學習中常常將他們分開學習,實際上兩者密不可分。
Looper與Handle的關係:
Looper是負責在線程裏建立消息循環的類,包括準備,開始循環,停止等整個消息循環的生命週期。Handle是負責不同線程之間消息的類,包括消息的發送,接受,清除等消息的生命週期。
但是隻有存在Looper的線程,纔會用到Handle。沒有Handle,Looper無法接收消息,也就無法實現功能。
我們通過Looper與Handle的源碼來分析:
Looper.java

    private static final ThreadLocal sThreadLocal = new ThreadLocal();  
    public static final void prepare() {  
            if (sThreadLocal.get() != null) {  
                throw new RuntimeException("Only one Looper may be created per thread");  
            }  
            sThreadLocal.set(new Looper());  
    }  

這裏說明通過prepare()創建Looper對象。同時Android也規定一個線程只能有一個Looper。
由上new Looper(),我們看 Looper的構造方法。

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

可以看到在Looper的構造函數中,創建了一個消息隊列對象mQueue,此時,調用Looper. prepare()的線程就建立起一個消息循環的對象。

再開始看Handle的源碼:
Handle.java

    final MessageQueue mQueue;  
     final Looper mLooper;  
    public Handler() {  
            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 = null;  
    }  

倒數第五行”Can’t create handler inside thread that has not called Looper.prepare()” 說明Handle的使用必須存在 Looper.prepare(),即必須存在信息隊列,這樣Handle才能找到信息。Handler通過mLooper = Looper.myLooper()綁定到線程的局部變量Looper上去,同時Handler通過mQueue =mLooper.mQueue獲得線程的消息隊列。

而沒有Handle處理信息即handleMessage (Message msg){},只有Looper的信息隊列在循環,信息就沒有價值,用武之地。

而我們平時用Handle時,只是在UI線程中卻沒有聲明Looper,是因爲UI線程本身默認含有Looper機制。這個我們程序報錯時經常看到“looper”。

最後總結工作原理:
1、 初始化Looper,啓動消息循環。

2、 綁定handler到CustomThread實例的Looper對象

3、 在Looper循環中,通過Handle發送或一直等待消息。

4、 Handle通過Looper得到消息,處理消息。

附代碼實例和更多Looper實現機制源碼:

    package com.zhuozhuo;  

    import android.app.Activity;  
    import android.os.Bundle;  
    import android.os.Handler;  
    import android.os.Looper;  
    import android.os.Message;  
    import android.util.Log;  
    import android.view.View;  
    import android.view.View.OnClickListener;  

    public class LooperThreadActivity extends Activity{  
        /** Called when the activity is first created. */  

        private final int MSG_HELLO = 0;  
        private Handler mHandler;  

        @Override  
        public void onCreate(Bundle savedInstanceState) {  
            super.onCreate(savedInstanceState);  
            setContentView(R.layout.main);  
            new CustomThread().start();//新建並啓動CustomThread實例  

            findViewById(R.id.send_btn).setOnClickListener(new OnClickListener() {  

                @Override  
                public void onClick(View v) {//點擊界面時發送消息  
                    String str = "hello";  
                    Log.d("Test", "MainThread is ready to send msg:" + str);  
                    mHandler.obtainMessage(MSG_HELLO, str).sendToTarget();//發送消息到CustomThread實例  

                }  
            });  

        }  





        class CustomThread extends Thread {  
            @Override  
            public void run() {  
                //建立消息循環的步驟  
                Looper.prepare();//1、初始化Looper  
                mHandler = new Handler(){//2、綁定handler到CustomThread實例的Looper對象  
                    public void handleMessage (Message msg) {//3、定義處理消息的方法  
                        switch(msg.what) {  
                        case MSG_HELLO:  
                            Log.d("Test", "CustomThread receive msg:" + (String) msg.obj);  
                        }  
                    }  
                };  
                Looper.loop();//4、啓動消息循環  
            }  
        }  
    }  

Google源碼:

private class Worker implements Runnable {
        private final Object mLock = new Object();
        private Looper mLooper;

        /**
         * Creates a worker thread with the given name. The thread
         * then runs a {@link android.os.Looper}.
         * @param name A name for the new thread

         */
        Worker(String name) {
            Thread t = new Thread(null, this, name);
            t.setPriority(Thread.MIN_PRIORITY);
            t.start();
            synchronized (mLock) {
                while (mLooper == null) {
                    try {
                        mLock.wait();
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }

        public Looper getLooper() {
            return mLooper;
        }

        public void run() {
            synchronized (mLock) {
                Looper.prepare();
                mLooper = Looper.myLooper();
                mLock.notifyAll();
            }
            Looper.loop();
        }

        public void quit() {
            mLooper.quit();
        }
    }
發佈了61 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章