學習一門技術或者看一篇文章最好的方式就是帶着問題去學習,這樣才能在過程當中有茅塞頓開、燈火闌珊的感受,記憶也會更深入。android
作 Android 開發確定離不開跟 Handler 打交道,它一般被咱們用來作主線程與子線程之間的通訊工具,而 Handler 做爲 Android 中消息機制的重要一員也確實給咱們的開發帶來了極大的便利。git
能夠說只要有異步線程與主線程通訊的地方就必定會有 Handler。c#
Handler 容許咱們發送延時消息,若是在延時期間用戶關閉了 Activity,那麼該 Activity 會泄露。bash
這個泄露是由於 Message 會持有 Handler,而又由於 Java 的特性,內部類會持有外部類,使得 Activity 會被 Handler 持有,這樣最終就致使 Activity 泄露。異步
解決該問題的最有效的方法是:將 Handler 定義成靜態的內部類,在內部持有 Activity 的弱引用,並及時移除全部消息。async
示例以下:ide
public class Part8HandlerActivity extends AppCompatActivity {
private Button bt_handler_send;
private static class MyHandler extends Handler {
//弱引用持有Part8HandlerActivity , GC 回收時會被回收掉
private WeakReference<Part8HandlerActivity> weakReference;
public MyHandler(Part8HandlerActivity activity) {
this.weakReference = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
Part8HandlerActivity activity = weakReference.get();
super.handleMessage(msg);
if (null != activity) {
//執行業務邏輯
Toast.makeText(activity,"handleMessage",Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_part8_handler);
//建立 Handler
final MyHandler handler = new MyHandler(this);
bt_handler_send = findViewById(R.id.bt_handler_send);
bt_handler_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new Runnable() {
@Override
public void run() {
//使用 handler 發送空消息
handler.sendEmptyMessage(0);
}
}).start();
}
});
}
@Override
protected void onDestroy() {
//移除全部回調及消息
myHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
}
複製代碼
注意:單純的在 onDestroy 移除消息並不保險,由於 onDestroy 並不必定執行。函數
獲取 Message 大概有以下幾種方式:工具
Message message = myHandler.obtainMessage(); //經過 Handler 實例獲取
Message message1 = Message.obtain(); //經過 Message 獲取
Message message2 = new Message(); //直接建立新的 Message 實例
複製代碼
經過查看源碼可知,Handler 的 obtainMessage() 方法也是調用了 Message 的 obtain() 方法oop
public final Message obtainMessage()
{
return Message.obtain(this);
}
複製代碼
經過查看 Message 的 obtain 方法
public static Message obtain(Handler h) {
//調用下面的方法獲取 Message
Message m = obtain();
//將當前 Handler 指定給 message 的 target ,用來區分是哪一個 Handler 的消息
m.target = h;
return m;
}
//從消息池中拿取 Message,若是有則返回,不然建立新的 Message
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
複製代碼
爲了節省開銷,咱們在使用的時候儘可能複用 Message,使用前兩種方式進行建立。
Handler 提供了一些列的方法讓咱們來發送消息,如 send()系列 post()系列 。
不過無論咱們調用什麼方法,最終都會走到 MessageQueue.enqueueMessage(Message,long) 方法。 以 sendEmptyMessage(int) 方法爲例:
//Handler
sendEmptyMessage(int)
-> sendEmptyMessageDelayed(int,int)
-> sendMessageAtTime(Message,long)
-> enqueueMessage(MessageQueue,Message,long)
-> queue.enqueueMessage(Message, long);
複製代碼
從中能夠發現 MessageQueue 這個消息隊列,負責消息的入隊,出隊。
實際上咱們在實例化 Handler 的時候 Handler 會去檢查當前線程的 Looper 是否存在,若是不存在則會報異常,也就是說在建立 Handler 以前必定須要先建立 Looper 。
public Handler(Callback callback, boolean async) {
//檢查當前線程是否持有 Looper
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//Looper 持有一個 MessageQueue
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
複製代碼
經過調用 Looper.prepare() 能夠在當前線程建立 Looper,而後調用 Looper.loop() 讓消息隊列循環起來。
代碼以下:
private static void prepare(boolean quitAllowed) {
//若是當前線程已經存在 Looper,則會拋出異常
//在主線程中調用 prepare 就會拋出此異常,由於主線程已經存在 Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//將建立的 Looper 對象存入線程的 ThreadLocal 中,保持惟一
sThreadLocal.set(new Looper(quitAllowed));
}
複製代碼
Looper.loop() 相關代碼
public static void loop() {
//會先獲取當前線程的 Looper,若是不存在拋出異常
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//而後獲取消息隊列
final MessageQueue queue = me.mQueue;
//..
for (;;) {
//不斷從 MessageQueue 中獲取消息
Message msg = queue.next(); // might block
//
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//..
try {
// 經過 handler 發送消息
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
//..
}
//..
//回收 Message
msg.recycleUnchecked();
}
}
複製代碼
Handler 的背後有着 Looper 以及 MessageQueue 的協助,三者通力合做,分工明確。 嘗試小結一下它們的職責,以下:
Looper :負責關聯線程以及消息的分發在該線程下從 MessageQueue 獲取 Message,分發給 Handler ;
MessageQueue :是個隊列,負責消息的存儲與管理,負責管理由 Handler 發送過來的 Message ;
Handler : 負責發送並處理消息,面向開發者,提供 API,並隱藏背後實現的細節。
Handler 發送的消息由 MessageQueue 存儲管理,並由 Loopler 負責回調消息到 handleMessage()。
線程的轉換由 Looper 完成,handleMessage() 所在線程由 Looper.loop() 調用者所在線程決定。
Handler 簡單易用的背後藏着工程師大量的智慧,要努力向他們學習。
但願看完本文能加深你對 Handler 的理解,對接下來學習有所幫助。