HandlerThread的必要性

在Android开发中,我们经常会遇到需要创建和处理多个线程的情况。有时候,我们需要在子线程中执行一些操作,然后将结果传递给主线程进行处理。为了实现这个功能,我们需要使用HandlerThread来简化子线程与子线程之间的通信过程。那么,为什么需要使用HandlerThread呢?

HandlerThread的本质

HandlerThread本质上就是一个普通的Thread,只不过在内部建立了一个Looper和一个消息队列。Looper负责处理消息队列中的事件,而Handler则是用于处理这些事件的具体实现。通过这种方式,HandlerThread为子线程提供了一个独立的运行环境,使得它们可以在这个环境中执行任务并与其他线程进行通信。

简化子线程与子线程之间的通信

由于HandlerThread为子线程提供了一个独立的运行环境,因此它可以简化子线程与子线程之间的通信过程。在传统的多线程编程中,我们需要使用各种方法来实现不同线程之间的数据交换,例如使用Intent、Bundle等。而在HandlerThread中,我们可以通过Handler来实现子线程与主线程之间的通信,这样就避免了繁琐的数据交换操作。

总之,HandlerThread在Android开发中具有重要的作用,它可以帮助我们简化子线程与子线程之间的通信过程,提高开发效率。

public class MainActivity extends AppCompatActivity {

private Handler handler1;

private Handler handler2;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

new MyThread1().start();

new MyThread2().start();

}

class MyThread1 extends Thread {

@Override

public void run() {

super.run();

Looper.prepare();

handler1 = new Handler() {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

System.out.println("threadName--" + Thread.currentThread().getName() + "messageWhat-" + msg.what);

}

};

try {

sleep(3000);

} catch (InterruptedException e) {

e.printStackTrace();

}

handler2.sendEmptyMessage(2);

Looper.loop();

}

}

class MyThread2 extends Thread {

@Override

public void run() {

super.run();

Looper.prepare();

handler2 = new Handler() {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

System.out.println("threadName--" + Thread.currentThread().getName() + "messageWhat-" + msg.what);

}

};

try {

sleep(4000);

} catch (InterruptedException e) {

e.printStackTrace();

}

handler1.sendEmptyMessage(5);

Looper.loop();

}

}

}

HandlerThread是一个继承自Thread的类,它可以用来处理子线程的消息队列,而不需要创建一个新的Looper。HandlerThread的用法可以参考这篇文章:

Handler是Android中的一个重要组件,它是用来处理消息队列中的消息的。HandlerThread和Handler之间的关系可以参考这篇文章:

```java

public class MainActivity extends AppCompatActivity {

private HandlerThread myHandlerThread;

private Handler handler;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

//创建一个线程,线程名字:handler-thread

myHandlerThread = new HandlerThread("handler-thread");

//开启一个线程

myHandlerThread.start();

//在这个线程中创建一个handler对象

handler = new Handler(myHandlerThread.getLooper()) {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

//这个方法是运行在 handler-thread 线程中的 ,可以执行耗时操作

Log.d("handler", "消息: " + msg.what + " 线程: " + Thread.currentThread().getName());

}

};

//在主线程给handler发送消息

handler.sendEmptyMessage(1);

new Thread(new Runnable() {

@Override

public void run() {

//在子线程给handler发送数据

handler.sendEmptyMessage(2);

}

}).start();

}

@Override

protected void onDestroy() {

super.onDestroy();

//释放资源

if (myHandlerThread != null) {

myHandlerThread.quit();

}

}

}

```

HandlerThread退出循环的方法有三种:handlerThreadquit()、handlerThread.quitSafely()和handlerThread.quitAndWait()。

相同点:将不再接受新的事件加入消息队列。无论是调用了quit方法还是quitSafely方法只会,Looper就不再接收新的消息。即在调用了Looper的quit或quitSafely方法之后,消息循环就终结了,这时候再通过Handler调用sendMessage或post等方法发送消息时均返回false,表示消息没有成功放入消息队列MessageQueue中,因为消息队列已经退出了。

不同点:当我们调用Looper的quit方法时,实际上执行了MessageQueue中的removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。当我们调用Looper的quitSafely方法时,实际上执行了MessageQueue中的removeAllFutureMessagesLocked方法,通过名字就可以看出,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。

需要注意的是Looper的quit方法从API Level 1就存在了,但是Looper的quitSafely方法从API Level 18才添加进来。

HandlerThread的主要作用是将主线程中的Looper任务转移到子线程中执行,从而降低主线程的压力,使主界面更加流畅,不会阻塞UI线程。HandlerThread本质上是一个线程,在线程内部,代码是串行处理的。

对于网络IO操作,HandlerThread并不适合,因为它只有一个线程,每一个任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

在使用HandlerThread时,需要注意在不需要使用的时候进行手动回收,以避免资源浪费。

以下是创建和启动HandlerThread的示例代码:

```java

// 创建一个线程,线程名字:handler-thread

myHandlerThread = new HandlerThread("handler-thread");

// 开启一个线程

myHandlerThread.start();

```

通过这段代码,我们成功创建了一个名为"handler-thread"的HandlerThread,并启动了这个线程。在实际应用中,我们需要在合适的时机回收HandlerThread以释放资源。

```java

public class HandlerThread extends Thread {

int mPriority;

int mTid = -1;

Looper mLooper;

public HandlerThread(String name) {

super(name);

mPriority = Process.THREAD_PRIORITY_DEFAULT;

}

protected void onLooperPrepared() {

}

@Override

public void run() {

mTid = Process.myTid();

Looper.prepare();

synchronized (this) {

mLooper = Looper.myLooper();

notifyAll();

}

Process.setThreadPriority(mPriority);

onLooperPrepared();

Looper.loop();

mTid = -1;

}

}

```

我们实际上是初始化并启动了一个线程。在run()方法中,我们调用了Looper.prepare()和Looper.loop()。prepare()方法创建了一个Looper对象,并将其放入该线程范围内的变量(sThreadLocal)中。在Looper对象的构造过程中,它初始化了一个MessageQueue,作为该Looper对象的成员变量。当没有消息时,loop()会阻塞,当有消息到来时,它会唤醒。

接下来,我们创建了一个handler:

```java

Handler handler = new Handler(myHandlerThread.getLooper());

```

```java

public Looper getLooper() {

if (!isAlive()) {

return null;

}

// 如果线程已经启动,等待直到looper被创建。

synchronized (this) {

while (isAlive() && mLooper == null) {

try {

wait();

} catch (InterruptedException e) {

}

}

}

return mLooper;

}

```

在这段代码中,`myHandlerThread.getLooper()`返回的就是我们在`run`方法中创建的`mLooper`。如果你足够细心,你会发现,在`run`方法里当`mLooper`创建完成后有个`notifyAll()`,而`getLooper()`中有个`wait()`。这是为什么呢?因为`mLooper`在一个线程中执行,而我们的handler是在UI线程初始化的,也就是说,我们必须等到`mLooper`创建完成,才能正确地返回`getLooper()`。`wait()`和`notify()`就是为了解决这两个线程的同步问题。