《Android Handler:线程间通信的核心实现》

在 Android 中,Handler 机制是一套用于线程间通信的核心机制,主要解决 "子线程无法直接更新 UI" 的问题(Android 规定 UI 操作必须在主线程执行,否则会抛出异常),同时也用于实现延迟任务、定时任务等场景。

1. Message(消息)

  • 是线程间传递的数据载体,可携带简单数据(如whatarg1arg2)或复杂对象(obj)。
  • 为了避免频繁创建对象,可通过Message.obtain()从消息池获取(复用机制),比new Message()更高效。

2. MessageQueue(消息队列)

  • 是一个单链表结构 的队列,用于存储Handler发送的Message,按消息的触发时间(when)排序(早触发的在前)。
  • 每个线程最多只有一个MessageQueue,由Looper创建并管理。

3. Looper(消息循环器)

  • 是 "消息循环" 的核心,负责不断从 MessageQueue 中取出消息 ,并分发到对应的Handler处理。
  • 每个线程最多只有一个Looper(通过ThreadLocal实现线程隔离,确保线程私有)。
  • 主线程(UI 线程)在启动时会自动初始化Looper(通过ActivityThread.main()方法),因此主线程可直接使用Handler;子线程若要使用Handler,需手动调用Looper.prepare()初始化Looper,再调用Looper.loop()启动循环。

4. Handler(处理器)

  • 负责发送消息到 MessageQueue (如sendMessage()post()等方法),并处理 Looper 分发的消息 (重写handleMessage()方法)。
  • 一个Handler关联一个Looper(创建时默认绑定当前线程的Looper),因此可通过Handler将消息从一个线程发送到另一个线程的MessageQueue

工作流程

  1. 初始化 Looper :线程启动时,若需使用 Handler 机制,需通过Looper.prepare()创建Looper和对应的MessageQueue(主线程默认初始化)。
  2. 创建 Handler :在目标线程(如主线程)创建Handler,它会自动绑定当前线程的LooperMessageQueue
  3. 发送消息 :其他线程(如子线程)通过HandlersendMessage()(发送Message)或post()(发送Runnable,内部会包装为Message)将消息加入MessageQueue
  4. 消息循环Looper.loop()启动死循环,不断从MessageQueue中取出消息(若队列空则阻塞,释放 CPU),并通过Message中关联的Handler分发消息。
  5. 处理消息Handler收到消息后,通过dispatchMessage()方法处理(优先执行MessageRunnable,其次是HandlerhandleMessage())。

关键细节

  • 线程与 Looper 的关系:1 个线程 → 1 个 Looper → 1 个 MessageQueue → N 个 Handler(多个 Handler 可绑定同一 Looper)。
  • Looper 的死循环为何不 ANR :当MessageQueue为空时,Looper会阻塞在next()方法(通过 Linux 的epoll机制休眠),不占用 CPU;有新消息时会被唤醒,因此不会导致 ANR。
  • 内存泄漏风险 :若Handler是 Activity 的非静态内部类,会持有 Activity 的强引用;若消息在队列中延迟未处理,会导致 Activity 无法被回收(内存泄漏)。解决:将Handler定义为静态内部类 ,并通过弱引用(WeakReference) 持有 Activity;在 Activity 销毁时(onDestroy())调用handler.removeCallbacksAndMessages(null)移除所有消息。

典型场景

  • 子线程执行耗时操作(如下载、数据库查询)后,通过Handler通知主线程更新 UI。
  • 实现延迟任务(如handler.postDelayed(runnable, 1000))。
  • 主线程向子线程发送指令(如停止子线程的任务)。

1.子线程→主线程通信

kotlin 复制代码
class MainActivity : AppCompatActivity() {
    companion object {
        private const val TAG = "HandlerDemo"
        private const val WHAT_UPDATE = 2
    }


    // 后台线程与其 Handler(示例使用 HandlerThread)
    private lateinit var workerThread: HandlerThread
    private lateinit var workerHandler: Handler

    // 界面元素:用于展示处理结果
    private lateinit var statusText: TextView
    private lateinit var actionButton: Button

    // Message 处理示例:在主线程中统一处理结构化消息
    private val messageHandler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                WHAT_UPDATE -> {
                    val text = "Updated: ${msg.obj}"
                    Log.d(TAG, "handleMessage WHAT_UPDATE: ${msg.obj}")
                    // 更新到界面
                    if (::statusText.isInitialized) {
                        statusText.text = text
                    }
                }
                else -> {
                    Log.d(TAG, "handleMessage what=${msg.what}")
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(R.layout.activity_main)
        // 绑定 TextView,用于展示主线程/后台线程的处理结果
        statusText = findViewById(R.id.statusText)
        actionButton = findViewById(R.id.actionButton)

        // 2) HandlerThread:创建后台线程并投递任务
        workerThread = HandlerThread("DemoWorker")
        workerThread.start()
        workerHandler = Handler(workerThread.looper)

        // 点击按钮后触发:仅演示子线程 -> 主线程通信
        actionButton.setOnClickListener {
            statusText.text = "Starting..."

            // 后台线程:执行任务并通过 Message 回到主线程
            workerHandler.post {
                Log.d(TAG, "workerHandler.post on ${Thread.currentThread().name}")
                Thread.sleep(300)
                val msg = messageHandler.obtainMessage(WHAT_UPDATE, "Result from worker")
                messageHandler.sendMessage(msg)
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        // 清理消息与回调,避免泄漏;安全退出后台线程
        messageHandler.removeCallbacksAndMessages(null)
        if (::workerThread.isInitialized) {
            workerThread.quitSafely()
        }
    }
}

2.实现延迟任务

kotlin 复制代码
// 后台线程:延迟启动任务,然后立即把结果发回主线程
Log.d(TAG, "schedule workerHandler.postDelayed(+5s)")
workerHandler.postDelayed({
    Log.d(TAG, "workerHandler.postDelayed on ${Thread.currentThread().name}")
    Thread.sleep(300)
    val msg = messageHandler.obtainMessage(WHAT_UPDATE, "Result from worker (delayed start)")
    messageHandler.sendMessage(msg)
}, 5000L)
相关推荐
CAD老兵4 小时前
打造高性能二维图纸渲染引擎系列(一):Batched Geometry 助你轻松渲染百万实体
前端·webgl·three.js
前端老宋Running4 小时前
微信小程序的操作日志收集模块
前端
CAD老兵4 小时前
打造高性能二维图纸渲染引擎系列(三):高性能 CAD 文本渲染背后的隐藏工程
前端·webgl·three.js
CAD老兵4 小时前
打造高性能二维图纸渲染引擎系列(二):创建结构化和可扩展的渲染场景
前端·webgl·three.js
王木风4 小时前
1分钟理解什么是MySQL的Buffer Pool和LRU 算法?
前端·mysql
Jerry_Rod4 小时前
vue 项目如何使用 mqtt 通信
前端·vue.js
云中雾丽4 小时前
Flutter中路由配置的各种方案
前端
不一样的少年_4 小时前
女朋友炸了:刚打开的网页怎么又没了?我反手甩出一键恢复按钮!
前端·javascript·浏览器
Renounce4 小时前
【Android】让 Android 界面 “动” 起来:动画知识点大起底
前端