概述
HandlerThread就是可以处理消息循环的线程,它是一个拥有Looper的线程,可以处理消息循环。简单理解就是一个Thread,内部使用了Looper。
我们都知道,除了在主线程,其他线程必须通过Looper.prepare()创建Looper、Looper.loop()开启消息循环。
举个栗子:
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private Button mBtnStart;
private Handler mChildThreadHandler; //子线程的Handler
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Thread thread = new ChildThread();
thread.start();
mBtnStart = (Button)findViewById(R.id.btn_start);
mBtnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mChildThreadHandler.sendEmptyMessage(0);
}
});
}
class ChildThread extends Thread{
@Override
public void run(){
Looper.prepare(); //给线程创建一个消息循环
mChildThreadHandler = new Handler(){
@Override
public void handleMessage(Message msg){
super.handleMessage(msg);
mBtnStart.setText("更新按钮文本");
}
};
Looper.loop(); //开始消息循环
}
}
}
我的天,在Handler更新UI,出现如下异常。
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
提示只有创建视图(主线程)的线程才能更新UI。mChildThreadHandler是在子线程中开启消息循环,所以没办法切换到主线程中更新UI。
HandlerThread就是在Thread中开启消息循环,但为什么要使用HandlerThread呢?当把Looper转到子线程处理,可以减轻主线程的工作量,使主界面更流畅。
再举一个栗子
用一个Handler更新UI,另一个Handler用于异步耗时任务
布局这里就不贴了,就一个Button一个TextView
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button mBtnStart;
private TextView mTvShow;
private Handler mChildHandler; //子线程的Handler
private HandlerThread mHandlerThread; //创建异步HandlerThread
private int flag;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTvShow = (TextView)findViewById(R.id.tv_show);
mBtnStart = (Button)findViewById(R.id.btn_start);
mBtnStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mChildHandler.sendEmptyMessage(0);
}
});
mHandlerThread = new HandlerThread("handlerThread");
mHandlerThread.start();
mChildHandler = new Handler(mHandlerThread.getLooper(), new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
//这里执行耗时操作后 更新UI
Message msg = Message.obtain();
msg.arg1 = ++flag;
msg.what = 0;
mUpdateUIHandler.sendMessage(msg);
return true;
}
});
}
private Handler mUpdateUIHandler = new Handler(){
@Override
public void handleMessage(Message message){
//这里用于更新UI
switch (message.what){
case 0:
mTvShow.setText("得到的数据"+message.arg1);
break;
}
}
};
@Override
protected void onDestroy() {
super.onDestroy();
mHandlerThread.quit();
}
}
效果
HandlerThread源码
public class More ...HandlerThread extends Thread {
int mPriority;
int mTid = - ;
Looper mLooper;
public More ...HandlerThread(String name) { //重点1
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public More ...HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void More ...onLooperPrepared() {
}
@Override
public void More ...run() { //重点2
mTid = Process.myTid();
Looper.prepare(); //重点3
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop(); //重点4
mTid = - ;
}
public Looper More ...getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean More ...quit() { //重点5
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean More ...quitSafely() { //重点6
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int More ...getThreadId() {
return mTid;
}
}
HandlerThread是一个Thread,传入的参数就是该线程的名称。
重点3、4通过内部自己创建Looper,开启消息循环,会一直循环,当明确不需要的时候,要记得销毁。
5、6的两个方法分别的作用为:
Looper的quit():将MessageQueue消息池的消息全部清空,无论是延迟消息还是非延迟消息。
Looper的quitSafely():只会清空MessageQueue消息池中所有的延迟消息,那些非延迟的消息会发给Handler去处理。
Looper的quit方法从API Level 1就存在了,但是Looper的quitSafely方法从API Level 18才添加进来。
再次强调:HandlerThread是串行执行,拥有自己的消息队列,不会阻塞UI线程。