Android异步处理机制:Handler,Looper,Mes
Android异步处理机制:Handler,Looper,MessageQueue
异步处理消息概念:
异步消息处理线程启动后会进入一个无限的循环体之中,每循环一次,从其内部的消息队列中取出一个消息,然后回调相应的消息处理函数,执行完成一个消息后则继续循环。若消息队列为空,线程则会阻塞等待。
Handler,Looper,MessageQueue三者的关系
每一个线程都拥有一个Looper对象,每一个Looper对象都持有一个MessageQueue(先进先出)。一个Looper可以和多个线程的Handler绑定起来。总结:Looper的创建会持有一个MessageQueue,然后进入一个无限循环体不断从该MessageQueue中获取消息,而消息的发送者可以是一个或者多个Handle。
解析
Looper
Looper的构造方法
private Looper(boolean quitAllowed) {
//创建了一个消息队列
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
Looper.prepare()
public static final void prepare() {
//sThreadLocal是一个ThreadLocal对象,可以在一个线程中存储变量
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
}
说明一个looper对象与对应线程绑定,且该线程有且仅有一个looper对象。如果第二次调用looper.prepare()方法会抛出异常。
Looper.loop()
public static void loop() {
final Looper me = myLooper();
//如果me为null说明在调用loop()方法之前没有为当前线程创建Looper对象,抛出异常。
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//进入无限循环,不断的从messageQueue中获取消息
for (;;) {
//从队列获取消息
Message msg = queue.next(); // might block
//如果消息是空,则队列中没有消息,return结束loop()方法,线程阻塞等待
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
//使用调用 msg.target.dispatchMessage(msg);把消息交给msg的target的dispatchMessage方法去处理。msg中的target就是handle。
msg.target.dispatchMessage(msg);
...
//释放消息占据的资源
msg.recycle();
}
}
/**
*获取线程ThreadLocal属性存储的looper对象
**/
public static Looper myLooper() {
return sThreadLocal.get();
}
综上所述,looper的作用就是与当前线程绑定,并且该线程只有一个looper。同时,looper持有一个MessageQueue,有且仅有一个。loop()方法无限循环的从MessageQueue中读取消息,并将message交给message的target的dispatchMessage(msg)处理。
Handler
Handler的构造方法
在使用Handler之前,我们必须对其实例化。
Handler必须和线程绑定在一起,在初始化Handler的时候一般通过指定Looper对象来绑定looper所在的线程,即给Handler指定Looper对象等于绑定到了Looper对象所在的线程中。Handler的消息处理回调会在该线程中执行。
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
...
//首先获取当前线程保存的looper对象,
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
//然后与该looper持有的MessageQueue绑定。
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
如果没有指定looper,那么handler会与当前创建handler的线程绑定,其消息回调处理也在该线程中执行。
可以通过Looper.myLoop()得到当前线程的looper对象或者调用Looper.getMainLooper()获得主线程的looper对象。
Handler向MessageQueue发送消息
handler send
最常用的sendMessage()方法
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
最后调用了sendMessageAtTime,在此方法内部直接获取MessageQueue然后调用了enqueueMessage方法
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//将handler实例赋值给msg的target属性。
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//调用消息队列的enqueueMessage()方法,
//就是将handler发送的消息保存到消息队列中去
return queue.enqueueMessage(msg, uptimeMillis);
}
Looper的loop()方法会取出每个msg然后执行msg.target.dispatchMessage(msg)去处理消息,其实就是派发给相应的Handler。
Handler工作流程:在线程中通过Looper.prepare()方法为当前线程创建Looper对象,并调用Looper.loop()方法无限循环地从messageQueue中获取handler发送过来的消息,并回调handler。dispatchMessage()方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//调用handler的sendMessage()方法,在源码中是一个空方法体。
//也就是我们在实例化Handler对象时,需要去覆写它,实现自己的处理逻辑。
handleMessage(msg);
}
}
注:在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢?这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。
Handler post
mHandler.post(new Runnable()
{
@Override
public void run()
{
Log.e("TAG", Thread.currentThread().getName());
mTxt.setText("yoxi");
}
});
Handler.post()方法中Runnable并没有创建线程。在这个run()方法中可以更新UI。其实Runnable只是发送了一条消息。
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
由此可见,源码中只是将Runnable对象作为message的callback属性。
注:产生一个Message对象,可以new ,也可以使用Message.obtain()方法;两者都可以,但是更建议使用obtain方法,因为Message内部维护了一个Message池用于Message的复用,避免使用new 重新分配内存。
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
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);
}
最终和handler.sendMessage一样,调用了sendMessageAtTime,然后调用了enqueueMessage方法,给msg.target赋值为handler,最终加入MessagQueue.
由于在getPostMessage()方法中我们给message的callback属性赋值(Runnable),所以这里需要进行判断到底回调handler还是runnable。
public void dispatchMessage(Message msg) {
//判断message对象的callback属性是否存在,若存在执行handlerCallback()方法。
//即调用runnable
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
MessageQueue
消息队列,用于存放handler发送过来的message
MessageQueue.enqueueMessage()方法将handler发送的消息插入队列中。MessageQueue.next()将消息按照先进先出的顺序取出。
总结
为了实现Android的UI线程安全,UI的相关操作只能在主线程(UI线程)中操作。但在开发中,需要开启多线程处理耗时操作,又要修改UI,所以就有了Handler传递机制。
[主线程(UI线程)定义:当程序第一次启动时,Android会同时启动一条主线程(Main Thread)
作用:主线程主要负责处理与UI相关的事件,所以主线程又叫UI线程)]
使用runOnUIThread()方法更新UI
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
从源码来看,首先判断当前线程是否是UI线程,如果不是,通过主线程的Handler来发送Runnable对象,实现当前线程与UI线程之间的信息传递;若当前线程是UI线程,则直接调用执行Runnable的run()方法。