Android Handler機制 - handleMessage究竟在哪個執行緒執行
關於Handler的原理,看了很多部落格,個人認為以下三篇文章講的不錯,第一篇篇幅最短,雖然沒有原始碼講解,但結合流程圖概括的很精煉;第二篇稍長,是CSDN部落格專家——鴻洋寫的,結合原始碼分析,簡單易懂;最後一篇就更詳細但也更冗長了:
ofollow,noindex">Android應用程式訊息處理機制
Android 非同步訊息處理機制 讓你深入理解 Looper、Handler、Message三者關係
Android 訊息處理機制(Looper、Handler、MessageQueue,Message)最後一篇中作者有條結論:
Handler 物件在哪個執行緒下構建(Handler的建構函式在哪個執行緒下呼叫),那麼Handler 就會持有這個執行緒的Looper引用和這個執行緒的訊息佇列的引用。因為持有這個執行緒的訊息佇列的引用,意味著這個Handler物件可以在任意其他執行緒給該執行緒的訊息佇列新增訊息,也意味著Handler的handleMessage 肯定也是在該執行緒執行的。
以上結論其實只概括了一部分,因為Handler的構造方法有很多種,以上結論只適用於不傳Looper的構造方法,諸如:
public Handler() public Handler(Callback callback)
這些構造方法預設與當前執行緒的Looper繫結 【通過mLooper = Looper.myLooper();】,所以說哪個執行緒建立了Handler物件,handleMessage就在哪個執行緒執行。
但是當使用引數中含有Looper的構造方法時,諸如:
public Handler(Looper looper) public Handler(Looper looper, Callback callback)
那麼此時無論Handler物件是在哪個執行緒構建的,該Handler物件所持有的Looper和MessageQueue都是構造方法中傳入的那個Looper,而這個Looper一般都是與其他執行緒繫結的(否則就沒必要使用這個構造函數了),此時相當於在當前執行緒下構造了一個與指定執行緒繫結的Handler物件,可以通過該Handler物件向指定執行緒傳送訊息,當然該Handler物件的handlerMessage也是執行在指定執行緒上的。
所以,可以得出結論,handler物件所繫結的執行緒其實並不取決於該handler物件由哪個執行緒構建,而是取決於該handler物件所繫結的Looper屬於哪個執行緒 。
以下的demo可以驗證結論:
MyHandlerThread.java:
package com.example.weishj.mytester.handler; import android.os.Handler; import android.os.Message; import android.util.Log; /** * Created by weishj on 2017/6/21. */ public abstract class MyHandlerThread implements Handler.Callback { protected final Handler handler; public MyHandlerThread() { Log.e("MyHandlerThread", "Create MyHandlerThread. tid=" + Thread.currentThread().getId()); android.os.HandlerThread t2 = new android.os.HandlerThread("MyHandlerThread"); t2.start(); Log.e("MyHandlerThread", "start t2. t2.tid=" + t2.getId()); this.handler = new Handler(t2.getLooper(), this); // handler持有的是t2的Looper和MessageQueue } public final boolean handleMessage(Message msg) { // 處理this.handler發過來的訊息 switch(msg.what) { case 1: Log.e("MyHandlerThread", "handled message. tid=" + Thread.currentThread().getId()); break; default: break; } return false; } }
Sub.java:
package com.example.weishj.mytester.handler; import android.os.Message; import android.util.Log; /** * Created by weishj on 2017/6/21. */ public class Sub extends MyHandlerThread { public Sub() { Log.e("Sub", "Create Sub. tid=" + Thread.currentThread().getId()); } // 對外提供一個方法,用於傳送訊息 public void sendMessage() { Message msg = new Message(); msg.what = 1; msg.obj = "test data"; super.handler.sendMessage(msg); } }
MainActivity.java:
package com.example.weishj.mytester; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import com.example.weishj.mytester.handler.Sub; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.e("MainActivity", "MainActivity onCreate. tid=" + Thread.currentThread().getId()); // 我在程式的某處, 如此呼叫 Thread t1 = new Thread(new Runnable() { @Override public void run() { Sub sub = new Sub(); sub.sendMessage(); } }); t1.start(); Log.e("MainActivity", "Start t1. t1.tid=" + t1.getId()); } }
demo執行後,最終輸出為:
06-22 10:36:44.607 2305-2305/com.example.weishj.mytester E/MainActivity: MainActivity onCreate. tid=1
06-22 10:36:44.608 2305-2305/com.example.weishj.mytester E/MainActivity: Start t1. t1.tid=1673
06-22 10:36:44.609 2305-2381/com.example.weishj.mytester E/MyHandlerThread: Create MyHandlerThread. tid=1673
06-22 10:36:44.610 2305-2381/com.example.weishj.mytester E/MyHandlerThread: start t2. t2.tid=1674
06-22 10:36:44.610 2305-2381/com.example.weishj.mytester E/Sub: Create Sub. tid=1673
06-22 10:36:44.613 2305-2382/com.example.weishj.mytester E/MyHandlerThread: handled message. tid=1674
handler物件是MyHandlerThread的一個成員變數,而MyHandlerThread是線上程1673構建的,所以這個handler物件也是在1673構建的,然而最終handleMessage是線上程1674上執行的,也就是構建handler物件時傳入的t2.getLooper()所對應的執行緒t2。