Android中關於Handler Looper理解


在Android中每個應用的UI線程是被保護的,不能在UI線程中進行耗時的操作,其他的子線程也不能直接進行UI操作。

為了達到這個目的Android設計了handler Looper這個系統框架。

首先講解在主線程中使用Handler時源碼跟蹤過程。

正常在activity的oncreate函數中定義個handler,這種情況下就是默認的主線程的handler,並去復寫該類的handleMessage()函數。

private final Handler mMessageHandler = new Handler(){
    @Override
    public void handleMessage(Message msg){
        ....;
    }
}

 在這里new 了一個Handler類,跟入系統代碼

106    /**
107     * Default constructor associates this handler with the {@link Looper} for the
108     * current thread.
109     *
110     * If this thread does not have a looper, this handler won't be able to receive messages
111     * so an exception is thrown.
112     */
113    public Handler() {
114        this(null, false);
115    }
188    public Handler(Callback callback, boolean async) {
189        if (FIND_POTENTIAL_LEAKS) {
190            final Class<? extends Handler> klass = getClass();
191            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
192                    (klass.getModifiers() & Modifier.STATIC) == 0) {
193                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
194                    klass.getCanonicalName());
195            }
196        }
197
198        mLooper = Looper.myLooper();
199        if (mLooper == null) {
200            throw new RuntimeException(
201                "Can't create handler inside thread that has not called Looper.prepare()");
202        }
203        mQueue = mLooper.mQueue;
204        mCallback = callback;
205        mAsynchronous = async;
206    }

最后需要對mQueue;mCallback;mAsynchronous這三個變量賦值。
這里注意 mLooper = Looper.myLooper(); 對mLooper的初始化。這里進入了Looper類

191    public static @Nullable Looper myLooper() {
192        return sThreadLocal.get();
193    }
68    // sThreadLocal.get() will return null unless you've called prepare().
69    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
92    private static void prepare(boolean quitAllowed) {
93        if (sThreadLocal.get() != null) {
94            throw new RuntimeException("Only one Looper may be created per thread");
95        }
96        sThreadLocal.set(new Looper(quitAllowed));
97    }
98

最后new Looper(quitAllowed) 在這里在當前thread中新建了一個Looper對象(所以從這里可以看出來Looper是屬於當前thread的)。
正常在我們自己new的線程中都需要調用Looper.prepare();語句來為當前線程new一個looper對象。但是對於UI線程中創建的looper是不需要的,因為在初始化UI線程時就已經寫好了。

正常UI線程初始化時調用prepareMainLooper這個函數。

99    /**
100     * Initialize the current thread as a looper, marking it as an
101     * application's main looper. The main looper for your application
102     * is created by the Android environment, so you should never need
103     * to call this function yourself.  See also: {@link #prepare()}
104     */
105    public static void prepareMainLooper() {
106        prepare(false);
107        synchronized (Looper.class) {
108            if (sMainLooper != null) {
109                throw new IllegalStateException("The main Looper has already been prepared.");
110            }
111            sMainLooper = myLooper();
112        }
113    }

對於一般的子線程需要繼續調用Looper.loop來啟動loop循環進行消息發送。
而同樣對於UI線程的looper同樣是在初始化過程中已經調用好了。

128    public static void loop() {
129        final Looper me = myLooper();
130        if (me == null) {
131            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
132        }
133        final MessageQueue queue = me.mQueue;
..............
142        for (;;) {
143            Message msg = queue.next(); // might block
144            if (msg == null) {
145                // No message indicates that the message queue is quitting.
146                return;
147            }
。。。。。。。。。。
158            msg.target.dispatchMessage(msg);

在這個loop()函數中就能真正看到消息循環機制。在一個死循環中for(;;)不斷從queue消息隊列中獲取messager,如果沒有將阻止在該端口等待下一個messager。
在獲取一個消息后則放入message中的targe中進行消息分發。

這里的target其實就是最開始在封裝一個message進行發送時傳入的handler,所以從這里也可以看出,最后消息還是通過handler傳入到它所在的線程中調用handleMessage()進行處理。

message.java 的成員變量:

public final class Message implements Parcelable {
   public int what;
   public int arg1;
   public int arg2;
   public Object obj;
   public Messenger replyTo;
   public int sendingUid = -1;
   /*package*/ static final int FLAG_IN_USE = 1 << 0;
   /** If set message is asynchronous */
   /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;
   /** Flags to clear in the copyFrom method */
   /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
   /*package*/ int flags;
   /*package*/ long when;
   /*package*/ Bundle data;
   /*package*/ Handler target
   /*package*/ Runnable callback;
   // sometimes we store linked lists of these things
   /*package*/ Message next;

在主線程中創建handler:

如上所述,如果在主線程中創建handler,並不需要經歷初始化looper等操作,因為在主線程剛創建的時候系統就自動為該主線程創建好了並啟動了循環,所以我們只需要在主線程中new一個handler並且重寫handleMessage方法,當其他的子線程需要更新UI的時候,只需要獲取該handle對象,並將信息發送即可。

 

在自己創建的子線程中創建handler:

當在自己創建的子線程中創建handler時,需要自己手動創建looper,初始化並啟動循環。

具體步驟:

1)初始化looper: Looper.prepare();

2)  創建looper對象: mLooper = Looper.myLooper();

3) 啟動looper循環: Looper.loop();

這樣就將子線程中的looper啟動起來,接下來就只要定義我們自己需要的handler並重寫handleMessage方法即可。

 

在Android中還提供一種常用的handler就是HandlerThread

創建步驟:

1)新建一個HandlerThread實例: mListenerThread = new HandlerThread("XXXX");

2) 啟動該handler實例:  mListenerThread.start();

3) 將該looper開啟循環: final Looper looper = mListenerThread.getLooper()

4)  定義該handler的handleMessage方法

HandlerThread uIhandlerThread = new HandlerThread("update");
uIhandlerThread.start();
finale Looper looper = uIhanderThread.getLooper();
if(looper != null){
   Handler uIhandler = new Handler(looper) {
       @Override
        public boolean handleMessage(Message msg) {
          ...
         return true;  
        }
    };
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM