Android 中 Handler 的用法詳解
Handler 是 Android 中用于線程間通信的重要機制,主要用于在不同線程之間發送和處理消息。以下是 Handler 的全面用法指南:
一、Handler 的基本原理
Handler 基于消息隊列(MessageQueue)和循環器(Looper)工作,主要組成:
- Message:攜帶數據的消息對象
- MessageQueue:消息隊列,存儲待處理的消息
- Looper:消息循環,不斷從隊列取出消息處理
- Handler:發送和處理消息的接口
二、基本用法
1. 創建 Handler(主線程)
// 在主線程創建Handler會自動關聯主線程的Looper
Handler mainHandler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {// 處理消息switch (msg.what) {case 1:String text = (String) msg.obj;textView.setText(text);break;}}
};
2. 發送消息
// 發送空消息
handler.sendEmptyMessage(1);// 發送帶what的消息
Message msg = handler.obtainMessage();
msg.what = 2;
msg.obj = "Hello Handler";
handler.sendMessage(msg);// 延遲發送
handler.sendEmptyMessageDelayed(1, 1000); // 1秒后發送
handler.sendMessageDelayed(msg, 2000); // 2秒后發送
3. 在子線程使用 Handler
new Thread(() -> {// 為當前線程創建LooperLooper.prepare();Handler threadHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {// 處理子線程消息}};// 開始消息循環Looper.loop();
}).start();
三、Handler 的常見使用場景
1. 更新 UI
new Thread(() -> {// 模擬耗時操作try {Thread.sleep(1000);// 通過Handler發送消息到主線程更新UIMessage msg = mainHandler.obtainMessage();msg.what = 1;msg.obj = "更新后的文本";mainHandler.sendMessage(msg);} catch (InterruptedException e) {e.printStackTrace();}
}).start();
2. 定時任務
// 延遲執行
handler.postDelayed(() -> {Toast.makeText(this, "5秒后執行", Toast.LENGTH_SHORT).show();
}, 5000);// 循環執行
final Runnable runnable = new Runnable() {@Overridepublic void run() {// 執行任務Log.d("Handler", "每隔1秒執行");// 再次post實現循環handler.postDelayed(this, 1000);}
};
handler.postDelayed(runnable, 1000);// 取消定時任務
handler.removeCallbacks(runnable);
3. 線程間通信
// 工作線程
class WorkerThread extends Thread {public Handler workerHandler;@Overridepublic void run() {Looper.prepare();workerHandler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(Message msg) {// 處理來自主線程的消息String task = (String) msg.obj;Log.d("WorkerThread", "執行任務: " + task);// 可以回傳結果給主線程Message resultMsg = mainHandler.obtainMessage();resultMsg.what = 2;resultMsg.obj = task + " 完成";mainHandler.sendMessage(resultMsg);}};Looper.loop();}
}// 主線程發送任務給工作線程
WorkerThread worker = new WorkerThread();
worker.start();// 等待workerHandler初始化
new Handler().postDelayed(() -> {if (worker.workerHandler != null) {Message msg = worker.workerHandler.obtainMessage();msg.obj = "下載文件";worker.workerHandler.sendMessage(msg);}
}, 1000);
四、高級用法
1. 使用 HandlerThread
// 創建HandlerThread
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();// 獲取HandlerThread的Looper創建Handler
Handler threadHandler = new Handler(handlerThread.getLooper()) {@Overridepublic void handleMessage(Message msg) {// 在后臺線程處理消息}
};// 發送消息
threadHandler.post(() -> {// 在HandlerThread中執行
});// 退出時釋放資源
handlerThread.quitSafely();
2. 避免內存泄漏
// 使用靜態內部類+弱引用
private static class SafeHandler extends Handler {private final WeakReference<Activity> activityRef;public SafeHandler(Activity activity) {super(Looper.getMainLooper());this.activityRef = new WeakReference<>(activity);}@Overridepublic void handleMessage(Message msg) {Activity activity = activityRef.get();if (activity != null && !activity.isFinishing()) {// 安全處理消息}}
}// 在Activity中使用
private SafeHandler safeHandler = new SafeHandler(this);
3. 使用 Message 的優化
// 復用Message對象(推薦)
Message msg = handler.obtainMessage(WHAT_ARG, obj);
handler.sendMessage(msg);// 設置回調代替繼承Handler
handler.sendMessage(Message.obtain(handler, () -> {// 回調處理
}));
五、注意事項
- 線程安全:Handler 與創建它的線程綁定,不能跨線程直接使用
- 內存泄漏:非靜態 Handler 內部類會持有外部類引用,Activity 銷毀時要移除回調
- Looper 準備:子線程使用 Handler 必須先調用 Looper.prepare()
- 消息堆積:避免發送過多消息導致消息隊列堵塞
- 及時清理:在 onDestroy() 中移除所有回調
@Override
protected void onDestroy() {super.onDestroy();handler.removeCallbacksAndMessages(null);if (handlerThread != null) {handlerThread.quitSafely();}
}