關于Handler的原理,看了很多博客,個人認為以下三篇文章講的不錯,第一篇篇幅最短,雖然沒有源碼講解,但結合流程圖概括的很精煉;第二篇稍長,是CSDN博客專家——鴻洋寫的,結合源碼分析,簡單易懂;最后一篇就更詳細但也更冗長了:
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。