Handler系列一:机制与使用

113 阅读2分钟

Handler用于处理消息(Message、Runnable对象)和线程间通信。

Handler的作用与应用

  1. 线程间通信

    • 在后台线程执行耗时任务,并在任务完成后通过Handler将结果发送回UI线程,以安全地更新UI元素。
  2. 延迟与定时执行

    • 利用postDelayed()sendMessageDelayed()方法,可以轻松实现任务的延迟执行或定时重复执行。
  3. 任务调度

    • Handler能够按照指定的顺序或时间策略安排任务执行,提供灵活的调度能力。
  4. 解耦与模块化

    • 通过将消息发送与接收逻辑与业务逻辑分离,Handler促进了代码的解耦,使得系统更加模块化,易于维护和扩展。

Handler机制的关键组件

  1. MessageQueue(消息队列)

    • 每个线程可拥有一个MessageQueue,用于存储待处理的消息和任务。
    • 这些消息和任务按照它们被添加到队列的顺序(或特定时间顺序,对于延迟消息)等待被处理。
  2. Handler

    • 作为消息和任务的发送者与接收者,Handler负责将RunnableMessage发送到特定线程的MessageQueue中。
    • 它也负责接收并处理来自MessageQueue的消息,通常这些处理操作在创建Handler的线程上执行。
  3. Looper

    • Looper用于启动和管理消息循环,使得线程能够不断地从MessageQueue中取出并处理消息。
    • 一个线程只能有一个Looper实例,但可以有多个Handler与之关联。 每个线程(除非特别地显式调用Looper.prepare()准备消息循环和调用Looper.loop()来启动)默认不运行消息循环。

示例说明

以下示例展示了如何在后台线程中执行耗时操作,并在完成后通过Handler在UI线程上更新界面:

// 在主线程(UI线程)上创建Handler
final Handler handler = new Handler(Looper.getMainLooper()); // 明确指定Looper

// 创建并启动后台线程
new Thread(new Runnable() {
    @Override
    public void run() {
        // 模拟耗时操作
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
        }

        // 使用Handler在UI线程上更新UI
        handler.post(new Runnable() {
            @Override
            public void run() {
                // 安全地在UI线程上更新TextView
                textView.setText("操作完成!");
            }
        });
    }
}).start();

注意:示例中明确指定了Looper.getMainLooper()作为Handler的构造参数,以确保Handler与UI线程的Looper关联,从而能够在UI线程上执行Runnable。这是处理UI更新时的标准做法。