Android Handler 的用法指南
Android 中 Handler 的用法詳解
Handler 是 Android 中用于線程間通信的重要機(jī)制,主要用于在不同線程之間發(fā)送和處理消息。以下是 Handler 的全面用法指南:
一、Handler 的基本原理
Handler 基于消息隊(duì)列(MessageQueue)和循環(huán)器(Looper)工作,主要組成:
- Message:攜帶數(shù)據(jù)的消息對象
- MessageQueue:消息隊(duì)列,存儲待處理的消息
- Looper:消息循環(huán),不斷從隊(duì)列取出消息處理
- Handler:發(fā)送和處理消息的接口
二、基本用法
1. 創(chuàng)建 Handler(主線程)
// 在主線程創(chuàng)建Handler會自動關(guān)聯(lián)主線程的Looper Handler mainHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { // 處理消息 switch (msg.what) { case 1: String text = (String) msg.obj; textView.setText(text); break; } } };
2. 發(fā)送消息
// 發(fā)送空消息 handler.sendEmptyMessage(1); // 發(fā)送帶what的消息 Message msg = handler.obtainMessage(); msg.what = 2; msg.obj = "Hello Handler"; handler.sendMessage(msg); // 延遲發(fā)送 handler.sendEmptyMessageDelayed(1, 1000); // 1秒后發(fā)送 handler.sendMessageDelayed(msg, 2000); // 2秒后發(fā)送
3. 在子線程使用 Handler
new Thread(() -> { // 為當(dāng)前線程創(chuàng)建Looper Looper.prepare(); Handler threadHandler = new Handler() { @Override public void handleMessage(Message msg) { // 處理子線程消息 } }; // 開始消息循環(huán) Looper.loop(); }).start();
三、Handler 的常見使用場景
1. 更新 UI
new Thread(() -> { // 模擬耗時操作 try { Thread.sleep(1000); // 通過Handler發(fā)送消息到主線程更新UI Message msg = mainHandler.obtainMessage(); msg.what = 1; msg.obj = "更新后的文本"; mainHandler.sendMessage(msg); } catch (InterruptedException e) { e.printStackTrace(); } }).start();
2. 定時任務(wù)
// 延遲執(zhí)行 handler.postDelayed(() -> { Toast.makeText(this, "5秒后執(zhí)行", Toast.LENGTH_SHORT).show(); }, 5000); // 循環(huán)執(zhí)行 final Runnable runnable = new Runnable() { @Override public void run() { // 執(zhí)行任務(wù) Log.d("Handler", "每隔1秒執(zhí)行"); // 再次post實(shí)現(xiàn)循環(huán) handler.postDelayed(this, 1000); } }; handler.postDelayed(runnable, 1000); // 取消定時任務(wù) handler.removeCallbacks(runnable);
3. 線程間通信
// 工作線程 class WorkerThread extends Thread { public Handler workerHandler; @Override public void run() { Looper.prepare(); workerHandler = new Handler(Looper.myLooper()) { @Override public void handleMessage(Message msg) { // 處理來自主線程的消息 String task = (String) msg.obj; Log.d("WorkerThread", "執(zhí)行任務(wù): " + task); // 可以回傳結(jié)果給主線程 Message resultMsg = mainHandler.obtainMessage(); resultMsg.what = 2; resultMsg.obj = task + " 完成"; mainHandler.sendMessage(resultMsg); } }; Looper.loop(); } } // 主線程發(fā)送任務(wù)給工作線程 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
// 創(chuàng)建HandlerThread HandlerThread handlerThread = new HandlerThread("MyHandlerThread"); handlerThread.start(); // 獲取HandlerThread的Looper創(chuàng)建Handler Handler threadHandler = new Handler(handlerThread.getLooper()) { @Override public void handleMessage(Message msg) { // 在后臺線程處理消息 } }; // 發(fā)送消息 threadHandler.post(() -> { // 在HandlerThread中執(zhí)行 }); // 退出時釋放資源 handlerThread.quitSafely();
2. 避免內(nèi)存泄漏
// 使用靜態(tài)內(nèi)部類+弱引用 private static class SafeHandler extends Handler { private final WeakReference<Activity> activityRef; public SafeHandler(Activity activity) { super(Looper.getMainLooper()); this.activityRef = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { Activity activity = activityRef.get(); if (activity != null && !activity.isFinishing()) { // 安全處理消息 } } } // 在Activity中使用 private SafeHandler safeHandler = new SafeHandler(this);
3. 使用 Message 的優(yōu)化
// 復(fù)用Message對象(推薦) Message msg = handler.obtainMessage(WHAT_ARG, obj); handler.sendMessage(msg); // 設(shè)置回調(diào)代替繼承Handler handler.sendMessage(Message.obtain(handler, () -> { // 回調(diào)處理 }));
五、注意事項(xiàng)
- 線程安全:Handler 與創(chuàng)建它的線程綁定,不能跨線程直接使用
- 內(nèi)存泄漏:非靜態(tài) Handler 內(nèi)部類會持有外部類引用,Activity 銷毀時要移除回調(diào)
- Looper 準(zhǔn)備:子線程使用 Handler 必須先調(diào)用 Looper.prepare()
- 消息堆積:避免發(fā)送過多消息導(dǎo)致消息隊(duì)列堵塞
- 及時清理:在 onDestroy() 中移除所有回調(diào)
@Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacksAndMessages(null); if (handlerThread != null) { handlerThread.quitSafely(); } }
到此這篇關(guān)于Android Handler 的用法詳解的文章就介紹到這了,更多相關(guān)Android Handler 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android Handler的使用詳解
- Android Handler使用案例詳解
- 深入Android HandlerThread 使用及其源碼完全解析
- Android使用Handler實(shí)現(xiàn)打地鼠游戲
- Android使用Handler實(shí)現(xiàn)倒計(jì)時功能
- Android使用Handler實(shí)現(xiàn)定時器與倒計(jì)時器功能
- Android開發(fā)使用Handler的PostDelayed方法實(shí)現(xiàn)圖片輪播功能
- Android 異步任務(wù) 設(shè)置 超時使用handler更新通知功能
- Android HandlerThread的使用及原理詳解
- Android使用Handler和Message更新UI
- Android開發(fā)使用UncaughtExceptionHandler捕獲全局異常
相關(guān)文章
Android實(shí)現(xiàn)手電筒電源鍵關(guān)閉功能
這篇文章主要介紹了Android實(shí)現(xiàn)手電筒電源鍵關(guān)閉功能,在打開手電筒之后,機(jī)器休眠,客戶要求點(diǎn)擊電源鍵,手電筒需要關(guān)閉,下面小編給大家分享實(shí)現(xiàn)代碼,需要的朋友可以參考下2017-11-11Android AOP 注解詳解及簡單使用實(shí)例(三)
這篇文章主要介紹了Android AOP 注解詳解及簡單使用實(shí)例(三)的相關(guān)資料,需要的朋友可以參考下2017-03-03Android7.0中關(guān)于ContentProvider組件詳解
本文描述了Android7.0中關(guān)于ContentProvider組件實(shí)現(xiàn)原理以及ContentProvider發(fā)布者和調(diào)用者這兩在Framework層是如何實(shí)現(xiàn)的。2017-11-11Flutter利用ORM框架簡化本地?cái)?shù)據(jù)庫管理詳解
使用?sqflite?相對來說還是有點(diǎn)復(fù)雜,比如遇到數(shù)據(jù)不兼容的時候需要手動轉(zhuǎn)換,增加了不少繁瑣的代碼。本篇我們就來介紹一個?ORM?框架,來簡化數(shù)據(jù)庫的管理,感興趣的可以了解一下2023-04-04Android開發(fā)中的ViewModel使用實(shí)戰(zhàn)案例
在Android應(yīng)用開發(fā)中,ViewModel作為架構(gòu)組件,重要的功能是管理UI數(shù)據(jù)與生命周期,文章深入分析ViewModel如何感知View的生命周期,以及其核心優(yōu)勢,包括生命周期感知、數(shù)據(jù)持久化和與UI層解耦,幫助開發(fā)者利用ViewModel優(yōu)化應(yīng)用架構(gòu),需要的朋友可以參考下2024-10-10Android超詳細(xì)講解組件ScrollView的使用
本節(jié)帶來的是Android基本UI控件中的第十個:ScrollView(滾動條),或者我們應(yīng)該叫他?豎直滾動條,對應(yīng)的另外一個水平方向上的滾動條:HorizontalScrollView,先讓我們來了解ScrollView2022-03-03android中Fragment+RadioButton實(shí)現(xiàn)底部導(dǎo)航欄
本篇文章主要介紹了android中Fragment+RadioButton實(shí)現(xiàn)底部導(dǎo)航欄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03Android 實(shí)現(xiàn)不同字體顏色的TextView實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 實(shí)現(xiàn)不同字體顏色的TextView實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-05-05