使用场景
程序需要执行一系列的耗时任务,这时候就需要启动额外的线程去执行耗时任务。如果每次遇到耗时任务都直接创建线程(new Thread() ),那么一系列耗时任务就要创建一系列线程,这些线程在任务完成后被系统回收销毁,并没有得到重复利用,造成资源浪费,增加系统负担。为此,可以使用HandlerThread在同一个线程中执行UI线程的异步任务。
demo
界面上2个按钮点击后执行耗时任务后,输出相应信息。
HandlerThreadDemo.png
public class HandlerThreadDemoActivity extends AppCompatActivity{
private static final String TAG = "HandlerThreadActivity";
private Button mBtnRequest1,mBtnRequest2;
private MyHandler mMyHandler;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handlerthread);
mBtnRequest1 = findViewById(R.id.btn_request1);
mBtnRequest1.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(mMyHandler != null){
String info = "MessageFrom1:" + System.currentTimeMillis();
Log.d(TAG, "==> onClick: sendMsg1");
//发送消息1
Message msg = mMyHandler.obtainMessage(1,info);
mMyHandler.sendMessage(msg);
}
}
});
mBtnRequest2 = findViewById(R.id.btn_request2);
mBtnRequest2.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(mMyHandler != null){
String info = "MessageFrom2:" + System.currentTimeMillis();
Log.d(TAG, "==> onClick: sendMsg2");
//发送消息2
Message msg = mMyHandler.obtainMessage(2,info);
mMyHandler.sendMessage(msg);
}
}
});
HandlerThread t1 = new HandlerThread("t1");
t1.start();
mMyHandler = new MyHandler(t1.getLooper());
}
@Override
protected void onStop() {
super.onStop();
Log.d(TAG, "==> onStop: ");
mMyHandler.removeCallbacksAndMessages(null);
}
static class MyHandler extends Handler{
MyHandler(Looper looper){
super(looper);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1:
try {
//消息1对应的耗时操作,模拟5s
Thread.sleep(5000);
Log.d(TAG, "==> handleMessage: msg1.");
showMessageInfo(((String) msg.obj));
}catch (InterruptedException e){
Log.d(TAG, "==> handleMessage: interruptedBy1");
}
break;
case 2:
try {
//消息1对应的耗时操作,模拟2s
Thread.sleep(2000);
Log.d(TAG, "==> handleMessage: msg2.");
showMessageInfo(((String) msg.obj));
}catch (InterruptedException e){
Log.d(TAG, "==> handleMessage: interruptedBy2");
}
break;
}
}
//输出处理完成消息
private void showMessageInfo(String message){
Log.d(TAG, "==> showMessageInfo:thread = " + Thread.currentThread().getName()
+ " message = " + message);
}
}
}
点击按钮1立即点击按钮2输出如下日志。先处理消息1的任务,耗时5s;尽管消息2早已发送,但对于消息2的处理在消息1处理完成之后。
03-08 03:18:25.915 7669-7669/com.lss.alpha D/HandlerThreadActivity: ==> onClick: sendMsg1
03-08 03:18:26.801 7669-7669/com.lss.alpha D/HandlerThreadActivity: ==> onClick: sendMsg2
03-08 03:18:30.917 7669-7723/com.lss.alpha D/HandlerThreadActivity: ==> handleMessage: msg1.
03-08 03:18:30.917 7669-7723/com.lss.alpha D/HandlerThreadActivity: ==> showMessageInfo:thread = t1 message = MessageFrom1:1520479105915
03-08 03:18:32.921 7669-7723/com.lss.alpha D/HandlerThreadActivity: ==> handleMessage: msg2.
03-08 03:18:32.921 7669-7723/com.lss.alpha D/HandlerThreadActivity: ==> showMessageInfo:thread = t1 message = MessageFrom2:1520479106801
从日志可知:
- 消息立即发出,并都在线程t1内执行了耗时任务,共用一个线程。
- 耗时任务按照消息收到的先后顺序依次执行。消息1处理时,后来的消息2的处理等待消息1处理完成后才能得到执行。
源码
public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
private @Nullable Handler mHandler;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
//获得当前线程的Looper
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
//开始轮询获得消息
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
//Looper没有创建,阻塞
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
....
}
从源码可以得知,HandlerThread创建了一个本地Looper对象,通过Handler向Looper的消息队列发送消息,Looper依次轮询消息队列中的消息,并在当前线程中调用消息的处理(耗时任务)。
操作
- 实例化HandlerThread,并调用start()方法开启线程
- 获得Looper对象,出入Looper对象实例化Handler
- Handler发送消息
- Handler在HandlerThread中处理消息
总结
HanderThread一个具有Looper的线程,可以按照消息的时间(msg.when)依次执行耗时任务。
- 优点: 不会堵塞主线程,减少对性能的消耗
- 缺点: 串行执行任务,处理效率比较低
网友评论