Handler是Android系统中一个非常重要的类,它主要用于在不同线程之间发送和处理消息。从源码角度分析Handler,有助于我们更好地使用Handler以及解决与Handler相关的问题。同时,了解Looper与Handler的关系也是非常关键的。
一个Handler允许发送和处理Message,通过关联线程的MessageQueue执行Runnable对象。每个Handler实例都和一个单独的线程及其消息队列绑定。可以将一个任务切换到Handler所在的线程中去执行。一个常见的用法就是子线程通过Handler更新UI。
Handler主要有以下两种用法:
1. 做出计划,在未来某个时间点执行消息和Runnable。
2. 线程调度,在其他线程规划并执行任务。
要使用好Handler,需要了解与其相关的Looper、Message和MessageQueue;不能孤立地看待Handler。Handler就像一个操作者(或者像一个对开发者开放的窗口),利用Looper、Message和MessageQueue来实现任务调度和处理。
Handler持有Looper的实例,直接持有looper的消息队列。在Handler的构造器中,我们可以看到Handler获取了Looper的消息队列。
下面我们来看一下Handler的一些属性和构造器:
- Handler类中持有的实例,持有looper,messageQueue等等。
- 在Handler的构造器中,我们可以看到Handler获取了Looper的消息队列。
接下来,我们来看一下Handler的使用方法:
1. handleMessage(Message msg):处理消息的方法,该方法通常被重写。
2. final boolean hasMessage(int what):检查消息队列中是否包含有what属性为指定值的消息。
3. final boolean hasMessage(int what, Object object):检查消息队列中是否包含有what和object属性指定值的消息。
4. sendEmptyMessage(int what):发送空消息。
5. final Boolean sendEmptyMessageDelayed(int what, long delayMillis):指定多少毫秒发送空消息。
6. final boolean sendMessage(Message msg):立即发送消息。
7. final boolean sendMessageDelayed(Message msg, long delayMillis):多少秒之后发送消息。
Handler.sendEmptyMessage(int what) 流程解析
获取一个Message实例,并立即将Message实例添加到消息队列中去。简要流程如下:首先调用prepare()方法,然后通过getLooper()方法获取Looper对象,再调用loop()方法进入消息循环。在消息循环中,从MessageQueue中取出消息进行处理,处理完成后调用handler.handleMessage()方法进行处理。如果需要取消任务,则调用cancel()方法取消与此Handler相关联的Message。
Handler取消任务时,可以通过调用cancel()方法来实现。该方法会取消掉与此Handler相关联的所有Message。相关的消息队列会执行取消指令。
Android 是消息驱动的,实现消息驱动有几个要素:消息的表示、消息队列、消息循环和消息处理。其中,消息表示使用Message类来表示;消息队列由MessageQueue维护;消息循环用于循环取出消息进行处理;消息处理则是通过Handler对象来实现的。
初始化消息队列时,在Looper构造器中即创建了一个MessageQueue,Looper持有消息队列的实例。发送消息时,通过Looper.prepare初始化好消息队列后就可以调用Looper.loop进入消息循环了,然后我们就可以向消息队列发送消息了。在看消息处理之前,先看一下消息是怎么被添加到消息队列的。Java层的消息都保存在了Java层MessageQueue的成员mMessages中,Native层的消息都保存在了Native Looper的mMessageEnvelopes中,这就可以说有两个消息队列,而且都是按时间排列的。
与Handler工作的几个组件Looper、MessageQueue各自扮演着不同的角色:Handler负责把消息发送给Looper管理的MessageQueue,并负责处理Looper分给它的消息;MessageQueue则负责管理Message;而Looper则负责每个线程只有一个,比如在UI线程中,系统会默认地初始化一个Looper对象。它负责管理MessageQueue,不断地从MessageQueue中取出来并将相对应的消息分给Handler进行处理。
Message 是一种用于在 Android 应用程序中传递和使用的消息对象。它包含描述信息和任意数据对象,可以被发送给特定的 Handler。每个 Message 实例都持有一个 Handler 对象,通常与一个 Activity 相关联。然而,这种关联可能导致内存泄漏问题,因为如果 Handler 持有 Activity 的引用,即使 Activity 已经销毁,Message 仍然可能留在消息队列中。
为了避免这种情况,当 Activity 销毁时,应该清除与 Activity 关联的 Handler 的消息队列。此外,Message 还提供了一些方法来重置自身、获取 Message 实例以及将消息发送给 Handler。
MessageQueue 是用于存储可以被 Looper 分发的 Message 的对象。Looper 是线程中运行的消息循环,通常由 Handler 将 Message 添加到 MessageQueue 中。要获取当前线程的 MessageQueue,可以使用 `getMainLooper()` 方法获取主线程的 Looper。
在 Android 应用程序中,Handler 和 Looper 通常在线程中交互。例如,当调用 `handler.post(message)` 方法后,Looper 开始运行并处理消息,直到循环停止。大多数情况下,开发者会通过 Handler 与消息循环进行交互。
以下是一个典型的 Handler 和 Looper 在线程中交互的例子:
```java
// 在子线程中创建 Looper
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare(); // 准备 Looper
Looper looper = Looper.myLooper(); // 获取当前线程的 Looper
Handler handler = new Handler(looper); // 创建与 Looper 关联的 Handler
// ... 在此处执行其他操作 ...
looper.loop(); // 开始处理消息,直到循环停止
}
}).start();
```
在这个例子中,我们首先在子线程中创建了一个 Looper,然后获取了当前线程的 Looper,并创建了一个与该 Looper 关联的 Handler。接下来,我们可以在其他地方执行操作,最后调用 `looper.loop()` 开始处理消息。
Looper 是 Android 中的一个重要组件,它主要负责维护一个消息队列,并在一个无限循环中不断地从队列中取出消息进行处理。每个线程只能有一个 Looper,而且必须在线程启动时创建。在 Android 的主线程(UI 线程)中,Looper 的实例会在应用启动时自动创建,而在其他线程中,则需要我们手动创建。
Handler 是 Android 中用于在不同线程之间发送和处理消息的类。它主要用于将任务调度到某个特定的线程的消息队列中执行,典型的应用场景是主线程(UI 线程)中进行 UI 的更新。
MessageQueue 是 Android 中用于存储消息的对象,它是 Handler 用来存储待处理消息的数据结构。
当子线程需要更新 UI 时,可以使用以下两种方式:
1. 在子线程中直接更新 UI:这种方式不推荐使用,因为这样会导致 UI 卡顿、闪烁等问题。如果必须使用这种方式,请确保子线程运行时间很短,并且不要在主线程中调用任何耗时操作。
2. 通过 Handler 将消息发送到主线程中:这种方式比较常用且安全,但是需要注意以下几点:
- 在发送消息之前,需要先获取当前线程所对应的 Handler;
- 在发送消息时,需要指定发送的目标 Handler;
- 在发送消息之后,需要等待目标 Handler 处理完该消息才能继续执行后续操作。
. SurfaceView:多媒体视频播放,也可以在子线程中更新UI
SurfaceView是一个用于显示2D图形的视图,它可以用于播放多媒体视频。由于SurfaceView涉及到硬件加速,因此需要在子线程中更新UI以避免阻塞主线程。
2. Handler的原理
Handler是Android系统中用于处理消息队列和线程间通信的一个类。它可以将一个Runnable对象封装成一个Message对象,然后将Message对象放入消息队列中。当子线程空闲时,会从消息队列中取出Message对象并执行其中的Runnable对象。
3. Handler导致的内存泄露如何解决?
内存泄露通常是由于没有正确释放资源导致的。在使用Handler时,需要注意在不再使用Handler时将其与Looper解绑,以便系统能够回收其占用的资源。
4. 如何使用Handler让子线程和子线程通信?
发送消息的子线程:创建Handler对象,将Runnable对象封装成Message对象,然后调用Handler的sendMessage()方法将Message对象发送到消息队列中。
接收消息的子线程:创建Handler对象,重写handleMessage()方法,在该方法中处理接收到的消息。
5. HandlerThread是什么、原理、使用场景?
HandlerThread是一个专门用于处理消息队列和线程间通信的线程。它的原理是通过创建一个独立的Looper来处理消息队列中的Message对象。使用场景包括在需要进行耗时操作的地方创建HandlerThread,以避免阻塞主线程。
6. IdleHandler是什么?
IdleHandler是一个自定义的Handler子类,用于检测线程是否处于空闲状态。当线程空闲时间超过设定的时间阈值时,IdleHandler会自动调用onIdle()方法。
7. 一个线程能否创建多个Handler,Handler和Looper之间的对应关系?
一个线程可以创建多个Handler,但每个Handler都需要关联一个独立的Looper。Handler和Looper之间的对应关系可以通过Handler的构造函数传入Looper对象来实现。
8. 为什么Android系统不建议子线程访问UI?
Android系统不建议子线程直接访问UI,因为UI控件不是线程安全的。如果多线程并发访问UI控件可能会出现不可预期的状态。为了避免这种情况,系统采用单线程模型来处理UI操作。
9. Looper死循环为什么不会导致应用卡死?
Looper死循环不会直接导致应用卡死,因为死循环中的代码会在每次循环时被暂停一段时间(通常是几百毫秒),然后再继续执行。这样可以避免过度消耗系统资源。
10. 使用Handler的postDelay后消息队列有什么变化?
使用Handler的postDelay()方法后,消息队列中会添加一个新的Message对象,该对象包含了要执行的Runnable对象以及延迟时间。当延迟时间到达后,系统会从消息队列中取出该Message对象并执行其中的Runnable对象。