《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)
相关推荐
xj75730653319 小时前
《python web开发 测试驱动方法》
开发语言·前端·python
IT=>小脑虎19 小时前
2026年 Vue3 零基础小白入门知识点【基础完整版 · 通俗易懂 条理清晰】
前端·vue.js·状态模式
IT_陈寒19 小时前
Python 3.12性能优化实战:5个让你的代码提速30%的新特性
前端·人工智能·后端
赛博切图仔19 小时前
「从零到一」我用 Node BFF 手撸一个 Vue3 SSR 项目(附源码)
前端·javascript·vue.js
爱写程序的小高19 小时前
npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree
前端·npm·node.js
loonggg19 小时前
竖屏,其实是程序员的一个集体误解
前端·后端·程序员
程序员爱钓鱼19 小时前
Node.js 编程实战:测试与调试 - 单元测试与集成测试
前端·后端·node.js
码界奇点19 小时前
基于Vue.js与Element UI的后台管理系统设计与实现
前端·vue.js·ui·毕业设计·源代码管理
时光少年19 小时前
Android KeyEvent传递与焦点拦截
前端
踢球的打工仔20 小时前
typescript-引用和const常量
前端·javascript·typescript