Handler常用用法

## 主线程 Handler 主要作用

在主线程中,`Looper`和`Message`都在主线程初始化,而`Handler`也在主线程初始化。当我们需要在子线程中调用该`Handler`,通知主线程进行一些操作时(通常是更新UI),我们可以使用以下方法:

```java

// 创建一个Handler对象

Handler handler = new Handler(Looper.getMainLooper());

// 在子线程中执行耗时任务

new Thread(new Runnable() {

@Override

public void run() {

// ...执行耗时任务...

// 将结果发送到主线程的Handler

handler.post(new Runnable() {

@Override

public void run() {

// 在这里更新UI

}

});

}

}).start();

```

## 子线程 Handler 主要作用

在子线程中,`Looper`和`Message`都在子线程初始化,而`Handler`也在子线程初始化。当我们需要在主线程中调用该`Handler`,通知子线程进行一些操作时(通常是网络操作、计算或其他耗时任务),我们可以使用以下方法:

```java

// 创建一个Handler对象

Handler handler = new Handler(new HandlerThread().start());

// 在主线程中执行耗时任务

new Thread(new Runnable() {

@Override

public void run() {

// ...执行耗时任务...

// 将结果发送到子线程的Handler

handler.post(new Runnable() {

@Override

public void run() {

// 在这里处理网络请求、计算等操作的结果

}

});

}

}).start();

```

### HandlerThread简介

`HandlerThread`就是使用了`Handler`机制的线程,其本质是一个线程`Thread`;属于上述介绍的子线程`Handler`机制。在运行`HandlerThread`线程的`run()`方法时,会在`run()`方法开始处调用`Looper.prepare()`方法,初始化该线程的`Looper`,然后在`run()`方法结束处调用`Looper.loop()`方法,开启无限循环,从`Looper`中的`MessageQueue`中循环获取消息,并转发给取出的`Message`消息对应的`Handler`进行相关任务处理。下面是`HandlerThread`线程的`run()`方法示例:

```java

@Override

public void run() {

Looper.prepare(); // 初始化 Looper 并准备接收消息队列的消息,但不立即启动消息循环体。如果当前没有其他线程调用 Looper.loop(),那么这个方法会立即返回。否则,它将阻塞当前线程直到消息循环体被启动。此方法主要用于多线程编程中,让某个线程能够接收消息队列的消息。一旦调用了 Looper.prepare(),就不能再调用 Looper.quit()。因为 Looper.quit() 是用来退出消息循环体的。当调用 Looper.quit()后,再调用 Looper.prepare()或 Looper.loop()都会抛出异常。所以通常情况下,我们应该先调用 Looper.quit(),然后再调用 Looper.prepare()或 Looper.loop()。只有在某些特殊情况下,才需要先调用 Looper.prepare(),如启动一个新的服务或者启动一个新的 Activity。在 Android Framework中,Service、Activity、BroadcastReceiver、ContentProvider等组件都是通过这种方式来实现与 UI 之间的通信的。另外,由于 IPC (进程间通信) 需要使用到跨进程通信技术,因此也需要使用到这种方式来实现跨进程通信。在这种情况下,我们需要先调用 Looper.prepare(),然后再调用 Looper.loop(),以便能够正确地处理跨进程通信的消息。