一、简介
在详细讲解这篇文章之前,应该有部分的Android初级开发者并没用使用过HandlerThread,最常使用的消息传递机制应该离不开Handler,那么Handler跟HandlerThread有什么不同呢,好处又在哪里?
名詞 | 解释 |
---|---|
Handler | 在android中负责发送和处理消息,通过它可以实现其他支线线程与主线程之间的消息通讯 |
Thread | 进程中执行运算的最小单位,亦即执行处理机调度的基本单位 |
HandlerThread | 一个继承自Thread的类HandlerThread,Android中没有对Java中的Thread进行任何封装,而是提供了一个继承自Thread的类HandlerThread类,这个类对Java的Thread做了很多便利的封装 |
二、作用
HandlerThread是Thread的子类,HandlerThread本身就是一个线程,可以实现工作线程和主线程之间的通信,只是这个线程内部有一个Looper,而这个Looper有一个消息队列MessageQue,它通过不断的用Looper去检查MessageQue然后取出消息交给Handler处理,UI主线程本身亦是如此,HandlerThread可以分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅。
三、优点
- HandlerThread本质上是通过继承Thread类和封装Handler类的使用,从而使得创建新线程和与其他线程进行通信变得更加方便易用。
- 降低主线程的压力,使主界面更流畅。
- HandlerThread拥有自己的消息队列,它不会干扰或阻塞UI线程。
四、具体实现
public class MainActivity extends AppCompatActivity {
Handler mainHandler,workHandler;
HandlerThread mHandlerThread;
TextView tv_content;
Button button1,button2,button3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 显示文本
tv_content= (TextView) findViewById(R.id.text1);
// 创建与主线程关联的Handler
mainHandler = new Handler();
/**
* 步骤1:创建HandlerThread实例对象
* name: 线程名
* priorit: 线程优先级
*/
mHandlerThread = new HandlerThread("handlerThread",Process.THREAD_PRIORITY_BACKGROUND);
/**
* 步骤2:启动线程
*/
mHandlerThread.start();
/**
* 步骤3:创建工作线程Handler,复写handleMessage()
*/
workHandler = new Handler(mHandlerThread.getLooper()){
@Override
// 消息处理的操作
public void handleMessage(Message msg)
{
switch(msg.what){
// 消息1
case 1:
try {
//延时操作
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 通过主线程Handler.post方法进行在主线程的UI更新操作
mainHandler.post(new Runnable() {
@Override
public void run () {
tv_content.setText("鱼王");
}
});
break;
// 消息2
case 2:
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
mainHandler.post(new Runnable() {
@Override
public void run () {
tv_content.setText("海王");
}
});
break;
default:
break;
}
}
};
/**
* 步骤4:使用工作线程Handler向工作线程的消息队列发送消息
* 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作
*/
// 点击Button1
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 通过sendMessage()发送
Message msg = Message.obtain();
//消息的标识
msg.what = 1;
// 消息的存放
msg.obj = "111";
workHandler.sendMessage(msg);
}
});
// 点击Button2
button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 通过sendMessage()发送
Message msg = Message.obtain();
//消息的标识
msg.what = 2;
// 消息的存放
msg.obj = "2222";
// b. 通过Handler发送消息到其绑定的消息队列
workHandler.sendMessage(msg);
}
});
// 点击Button3
button3 = (Button) findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//结束线程,即停止线程的消息循环
mHandlerThread.quit();
}
});
}
}
当我们调用Looper的quit方法时,实际上执行了MessageQueue中的removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(延迟消息是指通过sendMessageDelayed或通过postDelayed等方法发送的需要延迟执行的消息)还是非延迟消息。
总结
归根到底,HandlerThread可以分担MainLooper的工作量,降低了主线程的压力,使主界面更流畅,但是有是有引用HandlerThread的时候可能会引发内存泄漏,即:在Handler消息队列还有未处理的消息 / 正在处理消息时,此时若需销毁外部类MainActivity,但由于上述引用关系,垃圾回收器(GC)无法回收MainActivity,从而造成内存泄漏,下一篇博文会针对内存泄漏展开详细解说。