Android的Handler

本文详细介绍了Looper和Handler在Android开发中的作用,包括它们的使用方法、工作原理及如何与消息队列协同工作。重点阐述了消息的创建、发送、处理过程,并解释了Looper与Handler之间的关联。
  说到Handler,要先说说Looper类。

  Looper类的对象是和线程绑定的,它的主要功能就是为该线程创建一个消息循环。也即不断地去查询消息队列中是否存在消息,如果有则取出并处理。本质上有点类似Windows SDK编程中最后加上的几行代码:

    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

  Looper类的使用方法是:
  Looper类静态方法prepare()为当前线程绑定一个Looper对象;
  Looper类静态方法loop()让当前线程进入消息循环状态。

  进入消息循环后,当前线程其实就停留在loop()方法中了。要让线程继续往下走(执行loop()后面的代码),只有在处理消息时调用Looper类静态方法myLooper()得到和当前线程绑定的Looper对象,再调用它的quit()方法结束消息循环。


  有了消息循环后,就是Handler显身手的时候了。Handler负责创建消息,以及往Looper对象自带的消息队列里发送/移除消息。
  消息用Message对象表示。基本内容就是类型、参数以及处理消息的CallBack。

  关于CallBack有几种:

  • 一种是消息本身带有CallBack的,像用Handler的post()方法,可以设置消息的CallBack是一个Runnable对象,这样处理消息时就会执行这个Runnable
  • 一种是消息本身不带CallBack的,那么处理消息时就执行Handler对象或Handler类的CallBack,也即handleMessage()方法。

    Handler类中的方法实现:
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

  消息队列则其实是个链表,发送消息就是把消息插入到链表的合适位置。
  Handler的方法的接口看起来像能够延时发送,其实本质上都是马上插入链表的,不存在延时。只是这个链表是按时间排序的,而且不到指定的时间,消息不会被取出并处理。

  还有一个问题是Handler如何和Looper关联的,也就是消息处理是在哪个线程中执行的问题。

  这个其实是在创建Handler对象时完成的。创建Handler对象时可以指定Looper对象,如果没指定Looper对象,那么就认定是在当前线程中执行。当前线程是否已经绑定Looper对象,也即是否已经调用prepare()方法,将决定Handler对象是否创建成功。比较特殊的是系统会自动为Main Thread调用prepare()方法,所以在Main Thread创建Handler对象是很安全的。另外,系统提供了HandlerThread类,可以配合Handler使用,适合把消息处理放在一个专门的线程中。

### Android Handler 使用与常见问题 在 Android 开发中,`Handler` 是用于在不同线程之间通信的重要工具。它主要用于将任务(如 UI 更新)从后台线程传递到主线程执行,从而避免主线程阻塞并确保 UI 的流畅性。 #### Handler 的基本使用 `Handler` 通常与 `Looper` 和 `MessageQueue` 配合使用。每个 `Handler` 实例都与一个线程及其消息队列相关联。通过 `Handler`,可以发送和处理消息(`Message`)或运行 `Runnable` 对象。 以下是一个简单的 `Handler` 示例: ```java Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { // 更新 UI 的代码 } }); ``` 在子线程中使用 `Handler` 时,需要确保该线程已经调用了 `Looper.prepare()` 并启动了 `Looper.loop()`,否则会抛出异常。 #### 常见问题 1. **内存泄漏** 如果 `Handler` 持有对 `Activity` 或 `Context` 的引用,并且在子线程中长时间运行,可能会导致内存泄漏。为避免这种情况,通常建议使用静态内部类或弱引用(`WeakReference`)来持有外部类的引用。 ```java private static class MyHandler extends Handler { private final WeakReference<Activity> mActivityReference; public MyHandler(Activity activity) { mActivityReference = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { Activity activity = mActivityReference.get(); if (activity != null) { // 处理消息 } } } ``` 2. **消息延迟与顺序问题** 使用 `sendMessageDelayed()` 或 `postDelayed()` 可以实现延迟执行任务的功能。然而,如果多次发送相同的消息或 `Runnable`,可能会导致消息堆积,影响程序的响应速度。为避免此类问题,可以使用 `removeCallbacks()` 或 `removeMessages()` 来清理不再需要的消息。 3. **线程安全问题** 虽然 `Handler` 本身是线程安全的,但如果多个线程同时操作共享的数据结构,仍然需要额外的同步机制。例如,使用 `synchronized` 关键字或 `ReentrantLock` 来确保数据的一致性。 4. **主线程阻塞** 如果在 `Handler` 中执行耗时操作,可能会阻塞主线程,导致 ANR(Application Not Responding)错误。应避免在 `Handler` 中执行网络请求、数据库查询等耗时任务,建议使用 `AsyncTask`、`Thread` 或 `ExecutorService` 来处理这些操作。 5. **Looper 未初始化** 在非主线程中使用 `Handler` 时,必须手动调用 `Looper.prepare()` 来创建 `MessageQueue`,并在最后调用 `Looper.loop()` 来开始处理消息。如果忘记调用这些方法,会导致运行时异常。 ```java new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } }).start(); ``` 6. **消息优先级** 默认情况下,所有消息的优先级相同。如果需要处理高优先级的任务,可以通过 `Message` 的 `setAsynchronous()` 方法来标记异步消息,但这需要底层支持(如 `ViewRootImpl` 的 `Choreographer`)。 #### 总结 `Handler` 是 Android 中实现线程间通信的核心机制之一,但其使用过程中需要注意内存管理、线程安全、消息顺序等问题。合理使用 `Handler` 可以提升应用的响应能力和用户体验。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值