您的位置:首页 > 移动开发 > Android开发

Android开发Handler消息机制深入探究

2016-07-27 15:48 537 查看
提到Handler,大家不免会想到更新主界面或者延时操作。其实handler在安卓开发中扮演的主要角色就是随时更新主界面的。为什么要采用handler来更新主界面呢,这里又要谈到主线程的不安全原则。

我们知道一个应用启动时系统会为其创建一个进程,而每一Activity启动的时候又会形成一个线程,这个线程叫主线程。安卓的主线程是不安全的,因为从主线程中可以创建多个子线程来分配任务,一个activity的所有view都是唯一的,都有唯一的标识,如果在每个子线程中更新view,我们不能预知线程执行结果的先后顺序,也就无法预知什么时候才能更新view,所以造成结果就是view更新时的冲突问题。这也就是为什么从安卓2.0之后官方规定只能在主线程中更新界面了。子线程执行结果后通知主线程更新界面的桥梁便需要handler来帮忙,下面就深入探究一下handle的工作机制。

Handler的消息机制是一个系统,分别由handler,looper,message,messageQueue四个方面组成。先理解几个概念:handler,消息的处理者,负责消息的发送和处理。looper,消息的抽取者,处理消息的前奏。message,所谓的消息,里面包含消息Id。messageQueue,消息队列,handler发送的消息会暂存在消息队列里,然后采用FIFO先进先出的原则进行执行。Activity是在ActivityThread这个类的main方法里构造的,当构造好之后回调了OnCreate方法,之后调用UI线程的Looper.loop(),让looper开始工作,这个函数内部是一个循环,也即是主线程会一直执行下去。有些人可能会问这样下去会不会很耗cpu资源,其实不是这样,UI主线程其实一直处于半活动状态,当有消息来了他就会被唤醒,当没有消息的时候就会阻塞处于休眠状态。一个线程中只能有一个looper,Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。

关系图:



消息生成:

方法1:

Message msg = handler.obtainMessage();
msg.arg1 = i;
msg.sendToTarget();
方法2:
Message msg=new Message();
msg.arg1=i;
handler.sendMessage(msg);
第一种写法是message 从handler 类获取,从而可以直接向该handler 对象发送消息,减少了内存空间的开辟,节省资源。
第二种写法是直接调用 handler 的发送消息方法发送消息。

发送消息:

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}

在第一个代码片段中我们发现,handler在发送message的时候首先要找到所引用的消息队列。在第二个代码块中我们看到,Message的target设定成自己,目的是为了在处理消息环节中,Message能找到正确的Handler,最后将这个Message纳入到消息队列中。

抽取消息:

mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;

这里的looper处于一个死循环,时刻检索消息队列中的消息。

消息的分发:

public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}}

到这一步也算是最后一步消息即将传递到位,只等回调出来了。

附加说明:

在主线程(UI线程)里,如果创建Handler时不传入Looper对象,那么将直接使用主线程(UI线程)的Looper对象,系统已经帮我们创建了;

在其它线程里,如果创建Handler时不传入Looper对象,那么,这个Handler将不能接收处理消息。所以我们要自行在handler线程中创建一个looper,让他自行的跑起来,这样才能顺利接收和分发我们的消息了。

class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
至此今天我们针对handler,looper,messageQueue有一个中层次的探究,当然还有深一层的探究,等到后续我慢慢的再补充吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: