思考一下,假如我们需要同时下载A和B,下载A需要6s,下载B需要5s,在它们下载完成后Toast信息出来即可,此时HandlerThread便是一种解决方式之一。那么HandlerThread到底是什么?
- HandlerThread就是一种线程。
- HandlerThread和普通的Thread之间的区别就是HandlerThread在创建的时候会提供自己该线程的Looper对象。
我们在Actvity创建时系统会自动帮我们初始化好主线程的Looper,然后这个Looper就会管理主线程的消息队列。但是在我们创建子线程时,系统并不会帮我们创建子线程的Looper,需要我们自己手动创建,如下:
new Thread(){
@Override
public void run() {
super.run();
Looper.prepare();
Handler mHandler = new Handler(Looper.myLooper());
Looper.loop();
}
}.start();
所以HandlerThread就在内部帮我们封装了Looper的创建过程,从源码可以看到,HandlerThread集成于Thread,然后覆写run方法,进行Looper的创建,从而通过getLooper方法暴露出该线程的Looper对象
/* HandlerThread 源码 */
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
...
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;//默认优先级
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
@Override
public void run() {
mTid = Process.myTid(); //获取线程的tid
Looper.prepare();// 创建Looper对象
synchronized (this) {
mLooper = Looper.myLooper();//获取looper对象
notifyAll();//唤醒等待线程
}
Process.setThreadPriority(mPriority);
onLooperPrepared();// 该方法可通过覆写,实现自己的逻辑
Looper.loop();//进入循环模式
mTid = -1;
}
public Looper getLooper() {//获取HandlerThread线程中的Looper对象
if (!isAlive()) {// 当线程没有启动或者已经结束时,则返回null
return null;
}
// If the thread has been started, wait until the looper has been created.
//当线程已经启动,则等待直到looper创建完成
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();//休眠等待
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
//退出
//quit()与quitSafely()的区别,仅仅在于是否移除当前正在处理的消息。移除当前正在处理的消息可能会出现不安全的行为。
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit(); //普通退出
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely(); //安全退出
return true;
}
return false;
}
...
}
应用
很多时候,在HandlerThread线程中运行Loop()方法,在其他线程中通过Handler发送消息到HandlerThread线程。通过wait/notifyAll的方式,有效地解决了多线程的同步问题。
示例代码:
// Step 1: 创建并启动HandlerThread线程,内部包含Looper
HandlerThread handlerThread = new HandlerThread("gityuan.com");
handlerThread.start();
// Step 2: 创建Handler
Handler handler = new Handler(handlerThread.getLooper());
// Step 3: 发送消息
handler.post(new Runnable() {
@Override
public void run() {
System.out.println("thread id="+Thread.currentThread().getId());
}
});
或者 handler.postDelayed(Runnable r, long delayMillis)用于延迟执行。
实例:使用HandlerThread同时下载A和B
public class HandlerThreadActivity extends AppCompatActivity {
private TextView tv_A, tv_B;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler_thread);
tv_A = (TextView) findViewById(R.id.txt_dlA);
tv_B = (TextView) findViewById(R.id.txt_dlB);
final Handler mainHandler = new Handler();
final HandlerThread downloadAThread = new HandlerThread("downloadAThread");
downloadAThread.start();
Handler downloadAHandler = new Handler(downloadAThread.getLooper());
// 通过postDelayed模拟耗时操作
downloadAHandler.postDelayed(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "下载A完成", Toast.LENGTH_SHORT).show();
mainHandler.post(new Runnable() {
@Override
public void run() {
tv_A.setText("A任务已经下载完成");
}
});
}
}, 1000 * 5);
final HandlerThread downloadBThread = new HandlerThread("downloadBThread");
downloadBThread.start();
Handler downloadBHandler = new Handler(downloadBThread.getLooper());
// 通过postDelayed模拟耗时操作
downloadBHandler.postDelayed(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "下载B完成", Toast.LENGTH_SHORT).show();
mainHandler.post(new Runnable() {
@Override
public void run() {
tv_B.setText("B任务已经下载完成");
}
});
}
}, 1000 * 7);
}
}