应用程序启动时,会开启一个主线程(即UI线程),用来管理UI,监听用户点击,相应用户并发事件分发。所以主线程不进行耗时操作,否则出现ANR错误。这些耗时操作放到子线程中,由于Android子线程不是安全的,所以只能在主线程中更新UI。Handler就是用来子线程和创建Handler的线程进行通信的。
Handler的作用
1、按照时间计划,在未来某时刻,对处理一个消息或执行某个runnable实例。
2、把一个对另外线程对象的操作请求放入消息队列中,从而避免线程冲突。
Handler的使用
1、发送消息,在不同线程间发送消息通信,使用的方法为sendXXX():
sendEmptyMessage(int),发送一个空消息
sendMessage(message),发送一个message消息
sendMessageAtTime(message ,long),未来某一时间段点发送message消息
sendMessageDelayed(message ,long),延时N ms后发送message消息
2、计划任务,在未来执行某任务,使用的方法为postXXX():
post(Runnable),提交计划任务马上执行
postAtTime(Runnable ,long),提交计划任务在未来的时间点执行
postDelayed(Runnable , long),延时N ms提交计划任务
区别:sendXXX()发送的是消息,在handler里面操作UI;而postxxx()发送的是Runnable对象,在Runnable对象里面操作UI
在线程中创建Handler
在线程中创建Handler首先需要保证线程中包含Looper(UI线程中默认包含Looper)。为线程创建Looper的方法:
在线程的run()方法中先调用Looper.prepare()初始化Looper,然后再run()方法最后调用Looper.loop()开始循环处理消息,这样就创建好了Looper。
class MSecondThread extends Thread{
public Looper looper;
@Override
public void run() {
Looper.prepare();
looper = Looper.myLooper();
Looper.loop();
}
}
这就给子线程创建好了Looper,但是主线程想要给子线程传递消息的话,还需要给Handler指定相应的Looper,方法如下:
mHandler = new MyHadler(mSecondTd.looper){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Log.d(TAG, Thread.currentThread()+" ");
}
};
这样就创建了主线程给子线程传递消息的Handler和Looper。但是,这个过程中,在给Handler执行Looper时,经常会遇到Looper没有完成初始化的情况,往往需要采用一些等待之类的操作让子线程的Looper完成初始化,大大降低了效率,所以便有了HandlerThread。
HandlerThread
一种专门用户Handler通信的线程,上述情况使用HandlerThread可以简单快捷的实现,并且不用考虑Looper初始化的问题,例如
mSecondTd = new HandlerThread("HandlerThread");
mSecondTd.start();
mHandler = new Handler(mSecondTd.getLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
Log.d(TAG, Thread.currentThread().getName());
}
};
在点击事件中,使用mHandler.sendEmptyMessage(1)发送消息时,打印出来的线程名称为“HandlerThread”。
使用HandlerThread需要注意的是,HandlerThread所创建的子线程不能重写run()方法,否则不会执行HandlerMessage(),因为HandlerMesssage()本身就已经实现了run()。一个Handler在与HandlerThread进行绑定时,发现Looper为空,Handler则会一直等到知道Looper被创建出来为止,然后才继续执行后续的代码。所以我们重写了HandlerThread的run()方法,自然就不会去创建Looper对象了,绑定的相应的Handler就会永远处于等待状态,自然就不会执行handleMessage()了。使用HandlerThread我们不用关心多线程混乱,Looper为空等一系列问题。
Handler通信就是由别的线程使用指定线程的Handler向指定线程发送(sendXXX()\postXXX())消息,然后有指定线程消费消息的通信方式。需要注意的是主线程向子线程发送消息是,子线程需要使用Looper.prapare(),Looper.loop()方法准备创建Looper,并且要给Handler指定Looper。