目錄
- 什么是Handler
- 使用方式
- 源碼解析
- 內存泄漏問題
1. 什么是Handler
- 安卓線程間的一種通信機制
- 四大成員:Handler、Looper、MessageQueue 、Message
- Handler 中通過 ThreadLocal 保存 Looper,使每個線程有單獨唯一的 Looper(不同線程對同一個 ThreadLocal 進行的讀寫操作僅限于各自線程內部)
2. 使用方式
- sendMessage(message)
- post(runnable)
3. 源碼解析
Looper
- Looper.prepare():綁定當前線程,并創(chuàng)建MessageQueue對象
- Looper.loop():令當前線程死循環(huán),不斷從隊列中取出消息,執(zhí)行msg.target.dispatchMessage(msg) 方法
Handler
-
new Handler(looper):傳入looper(默認當前線程looper),進而
與looper中的MessageQueue相關聯(lián),looper所在線程即handler依附的線程 - sendMessage(msg):會設置msg的target為該handler本身,然后加入隊列
-
handler.sendMessage(msg) vs handler.post(runnable)
- post(r)方法調用了sendMessageDelay(msg),將runnable任務包裝成了msg的Callback屬性
- handle.dispatchMessage()首先判斷msg的Callback是否為空
- 若不為空,則執(zhí)行run()方法,否則才執(zhí)行handleMessage()方法
注意:
- Handler(looper) 的宿主線程是參數 looper 所依附的線程
- 無論Handler是在哪個線程中實例化的,只要它關聯(lián)的是主線程的Looper,就會由該Looper來回調handleMessage()方法,因為該Looper是在主線程中的,自然該方法就會運行在主線程中
- Handler.post() 并沒有創(chuàng)建新的線程
- Message.obtain() 方法維護了一個 Message 池用于 Message 的復用,更高效
4. 內存泄漏問題
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mImageView.setImageBitmap(mBitmap);
}
}
原因:
非靜態(tài)內部類持有外部類的引用
- 子線程執(zhí)行耗時操作(如網絡請求),而該線程持有 Handler 引用,Handler 持有 Activity 引用
- 若執(zhí)行的是 postDelayed(),會有一條 MessageQueue -> Message -> Handler -> Activity 引用鏈
解決:
- 將 Handler 聲明為靜態(tài)類,并持有一個對 Activity 的弱引用
static class MyHandler extends Handler {
WeakReference<Activity > mActivityReference;
MyHandler(Activity activity) {
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
mImageView.setImageBitmap(mBitmap);
}
}
}
- 若泄漏是因為 Handler 被 delay 的 Message 持有了引用,可在 Activity 的 onDestroy() 中執(zhí)行 mHandler.removeCallbacks() 方法