Android多线程通信:HandlerThread详解

## 一、背景介绍

在之前的博客中,我们已经学习了关于Android多线程中通信的基础概念和基本用法,通过现实世界两个人写信交流的过程来理解这些概念。然而,这套完整的细节确实很繁琐。幸运的是,Android为我们提供了一个简化的API——HandlerThread,通过使用HandlerThread,我们可以以一种简单的方式开启线程、进行线程通信。接下来,我们将详细介绍HandlerThread的使用方法。

## 二、HandlerThread简介

1. 参考文档:http://developer.android.com/reference/android/os/HandlerThread.html

2. 源码地址:Android-22源码中的`android/os/HandlerThread.java`文件

3. 重点方法:

- `protected void onLooperPrepared()`:在拓展类中需要重写的方法,完成准备工作,一般是对Handler进行定义。

- `public void run()`:在拓展HandlerThread时,如果要override run方法一定要记得调用父类的run()。

## 三、如何使用HandlerThread?

### 步骤1:创建HandlerThread实例

```java

private static final String TAG = "MyHandlerThread";

private HandlerThread mHandlerThread;

private Handler mHandler;

// ...

mHandlerThread = new HandlerThread(TAG);

mHandlerThread.start(); // 启动线程

mHandler = new Handler(mHandlerThread.getLooper()) { // 获取Looper并初始化Handler

@Override

public void handleMessage(Message msg) {

switch (msg.what) {

case 1:

// 处理消息1的逻辑

break;

case 2:

// 处理消息2的逻辑

break;

default:

break;

}

}

};

```

### 步骤2:发送消息给HandlerThread中的Handler进行处理

```java

Message message = Message.obtain(); // 获取Message对象

message.what = 1; // 设置消息类型为1或2

sendMessageToHandler(message); // 将消息发送给Handler进行处理

```

### 步骤3:从Handler接收消息并处理

```java

@Override

public void onMessageReceived(Message msg) {

int what = msg.what;

switch (what) {

case 1:

// 处理消息1的逻辑

break;

case 2:

// 处理消息2的逻辑

break;

default:

break;

}

}

```

### 步骤4:移除消息监听器(可选)

当不再需要接收消息时,可以移除消息监听器以避免内存泄漏。

在这篇文章中,我们将使用HandlerThread来演示如何在Android中创建线程。我们将通过一个简单的示例来说明HandlerThread的用法。首先,我们需要创建一个扩展的HandlerThread类,并在其中实现post方法以便与主线程进行通信。接下来,我们将在Activity中使用这个类,并通过Logcat打印日志来观察线程的执行情况。

1. 创建扩展的HandlerThread类:

```java

public class MyHandlerThread extends HandlerThread {

private static final String TAG = "MyThread";

public MyHandlerThread(String name) {

super(name);

}

@Override

protected void onLooperPrepared() {

super.onLooperPrepared();

Handler handler = new MyHandler(getLooper());

getThreadPool().execute(handler);

}

private static class MyHandler extends Handler {

public MyHandler(Looper looper) {

super(looper);

}

@Override

public void handleMessage(Message msg) {

Log.d(TAG, "handlerRequest: testing HandlerThread, thread: " + Thread.currentThread().getName());

// 处理消息的逻辑

Log.d(TAG, "message is handled, thread: " + Thread.currentThread().getName());

if (msg.what == WHAT_UPDATE_DATA) {

// do something;

} else if (msg.what == WHAT_SHOW_TOAST) {

Toast.makeText(MyHandlerThread.this.getApplicationContext(), msg.arg1, Toast.LENGTH_SHORT).show();

}

}

}

}

```

2. 在Activity中使用MyHandlerThread类:

```java

public class MainActivity extends AppCompatActivity {

private static final int WHAT_UPDATE_DATA = 0;

private static final int WHAT_SHOW_TOAST = 1;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

LogcatPrinter logcatPrinter = new LogcatPrinter("MyThread");

new MyHandlerThread("MyThread").start(); //开启线程

}

private static class LogcatPrinter implements Runnable {

private String tag;

private boolean running = true;

private final Looper mLooper;

private volatile boolean mCancelled = false;

private Message mMessage; //用于传递信息给子线程的对象;

private MyHandlerThread myHandlerThread; //自定义的线程对象;

private static MyHandlerThread myHandlerThreadInstance = null; //线程实例对象;

private static final int THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2 + 1; //线程池大小设置为可用的处理器数量乘以2加1;

private static BlockingQueue THREAD_POOL_QUEUE; //线程池任务队列对象;//new LinkedBlockingQueue(); //使用LinkedBlockingQueue作为线程池队列,因为它支持无界队列,不会出现OOM问题。如果不需要无界队列可以使用ArrayBlockingQueue。或者直接使用Vector也可以实现。但要注意Vector是线程安全的,所以不能保证所有情况下都能用。Vector适用于线程数比较少的情况。如果线程数比较多则需要考虑其他方式。如使用ScheduledExecutorService等工具类实现线程池管理。//THREAD_POOL_QUEUE=new ArrayBlockingQueue<>(100);//这里可以设置队列的大小。如果不需要无界队列的话。//THREAD_POOL_QUEUE=new LinkedBlockingQueue<>();//使用LinkedBlockingQueue作为线程池队列,因为它支持无界队列,不会出现OOM问题。如果不需要无界队列可以使用ArrayBlockingQueue。或者直接使用Vector也可以实现。但要注意Vector是线程安全的,所以不能保证所有情况下都能用。Vector适用于线程数比较少的情况。如果线程数比较多则需要考虑其他方式。如使用ScheduledExecutorService等工具类实现线程池管理。//THREAD_POOL_QUEUE=new LinkedBlockingQueue<>(100);//这里可以设置队列的大小。如果不需要无界队列的话。//THREAD_POOL_QUEUE=new LinkedBlockingQueue<>();//使用LinkedBlockingQueue作为线程池队列,因为它支持无界队列,不会出现OOM问题。如果不需要无界队列可以使用ArrayBlockingQueue。或者直接使用Vector也可以实现。但要注意Vector是线程安全的,所以不能保证所有情况下都能用。Vector适用于线程数比较少的情况。如果线程数比较多则需要考虑其他方式。如使用ScheduledExecutorService等工具类实现线程池管理。//THREAD_POOL_QUEUE=new LinkedBlockingQueue<>(100);//这里可以设置队列的大小。如果不需要无界队列的话。//THREAD_POOL_QUEUE=new LinkedBlockingQueue<>();//使用LinkedBlockingQueue作为线程池队列,因为它支持无界队列,不会出现OOM问题。如果不需要无界队列可以使用ArrayBlockingQueue。或者直接使用Vector也可以实现。但要注意Vector是线程安全的,所以不能保证所有情况下都能用。Vector适用于线程数比较少的情况。如果线程数比较多则需要考虑其他方式。如使用ScheduledExecutorService等工具类实现线程池管理。//THREAD_POOL_QUEUE=new LinkedBlockingQueue<>(100);//这里可以设置队列的大小。如果不需要无界队列的话。//THREAD_POOL_QUEUE=new LinkedBlockingQueue<>();//使用LinkedBlockingQueue作为线程池队列,因为它支持无界队列,不会出现OOM问题。如果不需要无界队列可以使用ArrayBlockingQueue。或者直接使用Vector也可以实现。但要注意Vector是线程安全的,所以不能保证所有情况下都能用。Vector适用于线程数比较少的情况。如果线程数比较多则需要考虑其他方式。如使用ScheduledExecutorService等工具类实