Android Handle机制详解

Android Handler 机制详解

Handler 是 Android 系统中用于线程间通信的核心机制,它构成了 Android 消息系统的基础。理解 Handler 机制对于开发流畅、高效的 Android 应用至关重要。

Handler 机制的核心组件

Android 的 Handler 机制主要由以下四个核心类组成:

  1. Handler - 消息的发送者和处理者
  2. Message - 消息的载体
  3. MessageQueue - 消息队列,存储待处理的消息
  4. Looper - 消息循环器,负责从 MessageQueue 中取出消息并分发

各组件详解

1. Message(消息)

Message 是线程间通信的数据载体,包含以下重要字段:

1
2
3
4
5
6
7
public int what;       // 消息标识
public int arg1;       // 整型参数1
public int arg2;       // 整型参数2
public Object obj;     // 任意对象
public long when;      // 消息处理时间
Handler target;        // 目标Handler
Runnable callback;     // Runnable回调

获取 Message 实例的最佳实践

1
2
3
4
// 推荐使用obtain()而不是直接new,因为会从消息池中复用
Message msg = Message.obtain();
msg.what = 1;
msg.obj = "Hello";

2. MessageQueue(消息队列)

  • 单链表结构实现的优先级队列,按消息处理时间(when)排序
  • 每个线程最多只有一个 MessageQueue
  • 主要操作:enqueueMessage() 和 next()

3. Looper(循环器)

Looper 的核心作用是不停地从 MessageQueue 中取出消息并分发:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public static void loop() {
    final Looper me = myLooper();
    final MessageQueue queue = me.mQueue;
    
    for (;;) {
        Message msg = queue.next(); // 可能阻塞
        if (msg == null) {
            return;
        }
        msg.target.dispatchMessage(msg); // 分发消息
        msg.recycleUnchecked(); // 回收消息
    }
}

重要方法

  • prepare(): 初始化当前线程的Looper
  • loop(): 开始消息循环
  • quit()/quitSafely(): 退出Looper

4. Handler(处理器)

Handler 是开发者最直接接触的类,主要功能:

  1. 发送消息:sendMessage(), post(Runnable)
  2. 处理消息:handleMessage(), dispatchMessage()

消息处理优先级

  1. 如果Message有callback(Runnable),则执行Runnable
  2. 如果Handler有全局Callback,则执行Callback
  3. 最后调用handleMessage()

Handler 机制工作原理

  1. 初始化

    • Looper.prepare() 创建Looper和MessageQueue
    • Looper.loop() 启动消息循环
  2. 发送消息

    • Handler发送消息到MessageQueue
    • 消息按when时间排序插入队列
  3. 处理消息

    • Looper不断从队列取消息
    • 将消息分发给目标Handler处理
    • 处理完成后回收消息

线程(Thread)、循环器(Looper)、处理者(Handler)之间的对应关系如下:

  • 1个线程(Thread)只能绑定 1个循环器(Looper),但可以有多个处理者(Handler)
  • 1个循环器(Looper) 可绑定多个处理者(Handler)
  • 1个处理者(Handler) 只能绑定1个循环器(Looper)

主线程消息循环

Android 主线程(UI线程)的消息循环是在ActivityThread中初始化的:

1
2
3
4
5
6
public static void main(String[] args) {
    Looper.prepareMainLooper(); // 初始化主线程Looper
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    Looper.loop(); // 开始消息循环
}

Handler 的使用场景

1. 线程间通信(子线程→主线程)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 在主线程创建Handler
Handler handler = new Handler(Looper.getMainLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 在主线程处理消息
    }
};

// 在子线程发送消息
new Thread(() -> {
    Message msg = handler.obtainMessage(1, "Data");
    handler.sendMessage(msg);
}).start();

2. 延迟任务

1
2
3
4
5
6
7
// 延迟1秒执行
handler.postDelayed(() -> {
    // 执行任务
}, 1000);

// 取消延迟任务
handler.removeCallbacks(runnable);

3. 定时任务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
private static final int MSG_UPDATE = 1;
private static final long INTERVAL = 1000; // 1秒

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        if (msg.what == MSG_UPDATE) {
            // 执行任务
            sendEmptyMessageDelayed(MSG_UPDATE, INTERVAL);
        }
    }
};

// 开始定时任务
handler.sendEmptyMessage(MSG_UPDATE);

// 停止定时任务
handler.removeMessages(MSG_UPDATE);

4.线程间通讯(主线程→子线程)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 子线程代码
Thread workerThread = new Thread(() -> {
    Looper.prepare(); // 初始化Looper
    Handler workerHandler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(Message msg) {
            // 处理主线程发来的消息
            Log.d("WorkerThread", "收到消息: " + msg.what);
        }
    };
    Looper.loop(); // 启动消息循环
});
workerThread.start();

// 主线程代码(如Activity中)
Handler mainHandler = new Handler(workerThread.getLooper()); // 需确保workerThread已启动
mainHandler.sendEmptyMessage(1); // 发送消息

或者

1
2
3
4
5
6
7
8
// 创建一个带有 Looper 的子线程
HandlerThread workerThread = new HandlerThread("MyHandlerThread");
handlerThread.start(); // 必须调用 start() 来启动线程和 Looper


// 主线程代码(如Activity中)
Handler mainHandler = new Handler(workerThread.getLooper()); // 需确保workerThread已启动
mainHandler.sendEmptyMessage(1); // 发送消息

Handler 内存泄漏问题

常见场景

1
2
3
4
5
6
7
8
public class MainActivity extends Activity {
    private final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // 处理消息
        }
    };
}

问题原因

  • Handler 持有 Activity 的隐式引用(匿名内部类)
  • Message 持有 Handler 引用
  • Message 可能长时间存在于 MessageQueue 中
  • 导致 Activity 无法被回收

解决方案

  1. 使用静态内部类 + WeakReference:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
private static class SafeHandler extends Handler {
    private final WeakReference<MainActivity> activityRef;
    
    public SafeHandler(MainActivity activity) {
        activityRef = new WeakReference<>(activity);
    }
    
    @Override
    public void handleMessage(Message msg) {
        MainActivity activity = activityRef.get();
        if (activity != null) {
            // 处理消息
        }
    }
}
  1. 在 Activity 销毁时移除所有消息:
1
2
3
4
5
@Override
protected void onDestroy() {
    super.onDestroy();
    handler.removeCallbacksAndMessages(null);
}

HandlerThread

HandlerThread 是 Android 提供的便捷类,集成了 Thread + Looper:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 创建HandlerThread
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();

// 创建关联该Looper的Handler
Handler handler = new Handler(handlerThread.getLooper()) {
    @Override
    public void handleMessage(Message msg) {
        // 在handlerThread线程处理消息
    }
};

// 退出时清理
handlerThread.quitSafely();

同步屏障机制(Sync Barrier)

同步屏障是 Handler 的高级特性,用于优先处理异步消息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// 插入同步屏障(API 23+)
MessageQueue queue = Looper.getMainLooper().getQueue();
Method method = MessageQueue.class.getDeclaredMethod("postSyncBarrier");
int token = (int) method.invoke(queue);

// 发送异步消息
Message msg = Message.obtain();
msg.setAsynchronous(true);
handler.sendMessage(msg);

// 移除同步屏障
Method removeMethod = MessageQueue.class.getDeclaredMethod("removeSyncBarrier", int.class);
removeMethod.invoke(queue, token);

应用场景:Choreographer 中用于优先处理垂直同步信号

性能优化建议

  1. 避免频繁创建 Message:使用 Message.obtain() 复用消息
  2. 及时清理消息:在不需要时调用 removeCallbacksAndMessages(null)
  3. 合理使用延迟消息:避免大量延迟消息堆积
  4. 谨慎使用同步屏障:不当使用可能导致UI卡顿
  5. 考虑使用 IdleHandler:在消息队列空闲时执行任务
1
2
3
4
Looper.myQueue().addIdleHandler(() -> {
    // 空闲时执行
    return false; // true表示保持,false表示移除
});

Handler 机制与协程对比

特性HandlerKotlin 协程
线程模型显式指定Handler/Looper通过Dispatchers指定上下文
内存泄漏风险需要手动处理通过CoroutineScope自动管理
代码可读性回调嵌套,可读性差顺序编写,可读性好
取消操作需要手动remove通过Job自动取消
适用场景简单线程切换、延迟任务复杂异步流程、并发任务

在现代 Android 开发中,对于复杂异步逻辑推荐使用协程,但 Handler 仍然是系统底层的基础机制,理解其原理对于解决深层次问题非常有帮助。

Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计