做android的都知道Handler机制在面试中是常客,但由于android自身对handler的实现方式(在ActivityThread中实现了 ),所以大家平时可能都会用,但是一说到handler机制的时候可能会想什么鬼,handler不是子线程更新主线程时用的吗?有什么机制?不错,在android中是更新主线程时常用的,确切的说是异步消息机制,用于多线程通讯。android从子线程更新主线程起始就是用handler从子线程向UI主线程发送了一条消息。
网上关于源码以及子线程与Ui线程的讲解已经很多了,我这里则不以子线程向UI线程通讯作为例子,我直接用两个线程通信介绍一下。因为我觉的对于刚开始没深入了解Handler的同学来讲,讲解Handler时还是尽量避开UI线程,搞不好越说越乱,我当年就是一片混乱。先看一下类的组成:
忽略activity,我们现在有两个线程One和Two,试想发送一条信息应该怎么操作?你可能说我定义一个全局变量啊。好吧,那一千条呢?下面我以考驾照举例:你学习科目二很久了,现在要参加科目二考试了。去了后你发现有两个地方,备考大厅(ThreadOne)和考试场地(ThreadTwo)。备考大厅会有人员安排考生一个个考试,但是考试要到场地去考(不能再备考大厅)。所以备考大厅安排某某去考试,并一个个通知场地人员考生正式开始考试。这事如果放在android中算是耗时操作了吧。
大致情形就是这样线程One告诉线程Two某某去场地考试了,线程Two收到消息后安排某某开始考试。没毛病吧?那么这是怎么一个消息呢,怎么处理呢?你们可以想想有哪些方式,但我只说handler机制怎么实现。进入主题:
先介绍一下登场嘉宾:Thread(男主角) Handler(女主角)Looper, MessageQueue, Message(配角)
首先看两段代码:
代码1:class ThreadTwo extends Thread{
@Override
public void run() {
//执行的代码
}
}
代码2:class ThreadTwo extends Thread{
@Override
public void run() {
Looper.prepare();
//执行的代码
Looper.loop();
}
}
很明显,下面多了两行代码。但是别小瞧这两行代码,大家都知道,线程是执行完当前代码就完成使命了,线程的任务也就结束了,这样的话,其它线程给它发消息它就接收不到了(因为它死了)
。那么怎么才能保证时刻接收消息,轮询听过吧?大概就是这样,给线程添加个消息循环,不断读取消息就行了。而looper就是这个作用,通过prepare()和loop()使线程进入循环。这样就可以不断读取消息了。消息从哪里循环读取呢?——MessageQueue。那MessageQueue的消息哪里来?——handler通过post或send方法传过来的。这样一个完整的消息循环就出来了,看个完整的例子吧:
public class HandlerActivity extends Activity {
private String TAG="HandlerActivityLog";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ThreadTwo two=new ThreadTwo();
two.start();//记住先运行two。否则handler会null的
ThreadOne t=new ThreadOne();
t.start();
}
class ThreadOne extends Thread{
@Override
public void run() {
//handler.getLooper().quit();
Message msg;
int total=1;
while(total<10){
msg=new Message();
msg.arg1=total;
handler.sendMessage(msg);
try {
sleep(1000);//模拟等待
} catch (InterruptedException e) {
e.printStackTrace();
}
total++;
}
}
}
private Handler handler=null;
class ThreadTwo extends Thread{
@Override
public void run() {
Looper.prepare();
handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//通过send方法传递的消息在这里处理;比如handler.sendEmptyMessage()
Log.d(TAG, msg.arg1+"号考生开始考试!");
}
};
Looper.loop();
}
}
}
接下来请其实ThreadTwo就相当于UI主线程,它用来接收另一个线程给它的消息(只是这个线程不是它的子线程)。
总结:handler通过post或者send发送一个消息Message——MessageQueue将消息放入队列——looper循环读取
ps:1.handler在new Handler(Looper looper)时默认不传递参数,获取的是当前线程的looper
2.handler的post和send方法:
send发送一条消息,在public void handleMessage(Message msg) {}中回调
post一个Runnable对象,直接执行Runnable下的方法。
比如:
handler.postDelayed(new Runnable() {
@Override
public void run() {}
}, 1000);