Handler是Android中处理异步消息的机制。Looper、Handler、MessageQueue、Message归纳来讲就是:Looper负责的就是建立一个MessageQueue,而后进入一个无限循环体不断从该MessageQueue中读取消息Message,而后回调相应的消息处理函数,而消息的建立者就是一个或多个Handler,执行完成一个消息后则继续循环。android
消息队列MessageQueue就是存放消息的队列。那队列中存储的消息是什么呢?假设咱们在UI界面上单击了某个按钮,而此时程序又刚好收到了某个广播事件,那咱们如何处理这两件事呢? 由于一个线程在某一时刻只能处理一件事情,不能同时处理多件事情,因此咱们不能同时处理按钮的单击事件和广播事件,咱们只能挨个对其进行处理,只要挨个处理就要有处理的前后顺序。为此Android把UI界面上单击按钮的事件封装成了一个Message,将其放入到MessageQueue里面去,即将单击按钮事件的Message入栈到消息队列中,而后再将广播事件的封装成以Message,也将其入栈到消息队列中。也就是说一个Message对象表示的是线程须要处理的一件事情,消息队列就是一堆须要处理的Message的池。线程Thread会依次取出消息队列中的消息,依次对其进行处理。spring
MessageQueue中有两个比较重要的方法,一个是enqueueMessage方法,一个是next方法。enqueueMessage方法用于将一个Message放入到消息队列MessageQueue中,next方法是从消息队列MessageQueue中阻塞式地取出一个Message。bash
消息队列MessageQueue只是存储Message的地方,真正让消息队列循环起来的是Looper,这就比如消息队列MessageQueue是个水车,那么Looper就是让水车转动起来的河水,若是没有河水,那么水车就是个静止的摆设,没有任何用处,Looper让MessageQueue动了起来。多线程
Looper是用来使线程中的消息循环起来的。默认状况下当咱们建立一个新的线程的时候,这个线程里面是没有消息队列MessageQueue的。为了可以让线程可以绑定一个消息队列,咱们须要借助于Looper:首先咱们要调用Looper的prepare方法,而后调用Looper的loop方法。异步
public static final void prepare() {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(true));
复制代码
sThreadLocal是一个ThreadLocal对象,能够在一个线程中存储变量。能够看到,将一个Looper的实例放入了ThreadLocal,而且先判断了sThreadLocal.get是否为null,不然抛出异常。这也就说明了Looper.prepare()方法不能被调用两次,同时也保证了一个线程中只有一个Looper实例。async
上面的代码执行了Looper的构造函数,咱们看一下其代码:ide
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mRun = true;
mThread = Thread.currentThread();
}
复制代码
在构造函数中,建立了一个消息队列MessageQueue,并将其赋值给其成员字段mQueue,这样Looper也就与MessageQueue经过成员字段mQueue进行了关联。函数
public static void loop() {
final Looper me = myLooper();
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();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); if (ident != newIdent) { Log.wtf(TAG, "Thread identity changed from 0x" + Long.toHexString(ident) + " to 0x" + Long.toHexString(newIdent) + " while dispatching to " + msg.target.getClass().getName() + " " + msg.callback + " what=" + msg.what); } msg.recycle(); } } 复制代码
上面有几行代码是关键代码:oop
1. final Looper me = myLooper();post
myLooper()方法直接返回了sThreadLocal存储的Looper实例,若是me为null则抛出异常,也就是说looper方法必须在prepare方法以后运行。
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
复制代码
public static Looper myLooper() {
return sThreadLocal.get();
}
复制代码
2. final MessageQueue queue = me.mQueue;
拿到该looper实例中的消息队列mQueue。变量me是经过静态方法myLooper()得到的当前线程所绑定的Looper,me.mQueue是当前线程所关联的消息队列。
3. for (;;)
进入了循环。咱们发现for循环没有设置循环终止的条件,因此这个for循环是个无限循环。
4. Message msg = queue.next(); // might block
取出一条消息,若是没有消息则阻塞。咱们经过消息队列MessageQueue的next方法从消息队列中取出一条消息,若是此时消息队列中有Message,那么next方法会当即返回该Message,若是此时消息队列中没有Message,那么next方法就会阻塞式地等待获取Message。
5. msg.target.dispatchMessage(msg);
msg的target属性是Handler,该代码的意思是让Message所关联的Handler经过dispatchMessage方法让Handler处理该Message。
6. msg.recycle();
释放消息占据的资源。
1.与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
2.loop()方法,不断从MessageQueue中去取消息,交给消息Message的target属性,即Handler的dispatchMessage去处理。
使用Handler以前,咱们都是初始化一个实例,好比用于更新UI线程,咱们会在声明的时候直接初始化,或者在onCreate中初始化Handler实例。因此咱们首先看Handler的构造方法,看其如何与MessageQueue联系上的,它在子线程中发送的消息(通常发送消息都在非UI线程)怎么发送到MessageQueue中的。
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
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;
}
复制代码
上面有几行代码是关键代码:
1. public Handler(Callback callback, boolean async)
Handler.Callback是用来处理Message的一种手段,若是没有传递该参数,那么就应该重写Handler的handleMessage方法,也就是说为了使得Handler可以处理Message,咱们有两种办法:
(1)向Hanlder的构造函数传入一个Handler.Callback对象,并实现Handler.Callback的handleMessage方法。
(2)无需向Hanlder的构造函数传入Handler.Callback对象,可是须要重写Handler自己的handleMessage方法。
//在主线程中建立mHandler,因此自动绑定主线程
private Handler mHandler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
System.out.println("handleMessage thread id " + Thread.currentThread().getId());
System.out.println("msg.arg1:" + msg.arg1);
System.out.println("msg.arg2:" + msg.arg2);
System.out.println("msg.obj:" + msg.obj.toString());
System.out.println("msg.setDate:" + msg.getData().get("QQ"));
textview.setText("success");
break;
}
}
};
private Handler mHandler2 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
switch (msg.what){
case 1:
System.out.println("handleMessage thread id " + Thread.currentThread().getId());
System.out.println("msg.arg1:" + msg.arg1);
System.out.println("msg.arg2:" + msg.arg2);
System.out.println("msg.obj:" + msg.obj.toString());
System.out.println("msg.setDate:" + msg.getData().get("QQ"));
textview.setText("success");
break;
}
return false;
}
});
复制代码
也就是说不管哪一种方式,咱们都得经过某种方式实现handleMessage方法,这点与Java中对Thread的设计有殊途同归之处。
在Java中,若是咱们想使用多线程,有两种办法:
(1)向Thread的构造函数传入一个Runnable对象,并实现Runnable的run方法。
(2)无需向Thread的构造函数传入Runnable对象,可是要重写Thread自己的run方法。
2. mLooper = Looper.myLooper();
首先经过Looper.myLooper()获取了当前线程保存的Looper实例。
3.mQueue = mLooper.mQueue;
而后再获取该Looper实例中保存的消息队列MessageQueue,这样就保证了Handler的实例与Looper实例中MessageQueue关联上了。
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) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
复制代码
上面有几行代码是关键代码:
1. msg.target = this;
该代码将Message的target绑定为当前的Handler。
2. queue.enqueueMessage;
变量queue表示的是Handler所绑定的消息队列MessageQueue,经过调用queue.enqueueMessage(msg, uptimeMillis)咱们将Message放入到消息队列中。
如今已经很清楚了Looper会调用prepare()和loop()方法,在当前执行的线程中保存一个Looper实例,这个实例会保存一个MessageQueue对象,而后当前线程进入一个无限循环中去,不断从MessageQueue中读取Handler发来的消息。而后再回调建立该消息的Handler中的dispathMessage方法。Handler的dispatchMessage的源码以下:
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
复制代码
上面有几行代码是关键代码:
1. if (msg.callback != null) { handleCallback(msg); }
首先会判断msg.callback存不存在,msg.callback是Runnable类型,若是msg.callback存在,那么说明该Message是经过执行Handler的postXXX系列方法将Message放入到消息队列中的,这种状况下会执行handleCallback(msg), handleCallback源码以下:
private static void handleCallback(Message message) {
message.callback.run();
}
复制代码
这样咱们咱们就清楚地看到咱们执行了msg.callback的run方法,也就是执行了postXXX所传递的Runnable对象的run方法。
2. else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } }
若是咱们不是经过postXXX系列方法将Message放入到消息队列中的,那么msg.callback就是null,代码继续往下执行,接着咱们会判断Handler的成员字段mCallback存不存在。mCallback是Hanlder.Callback类型的,咱们在上面的Handler构造函数提到过,在Handler的构造函数中咱们能够传递Hanlder.Callback类型的对象,该对象须要实现handleMessage方法,若是咱们在构造函数中传递了该Callback对象,那么咱们就会让Callback的handleMessage方法来处理Message。
3.handleMessage(msg);
若是咱们在构造函数中没有传入Callback类型的对象,那么mCallback就为null,那么咱们会调用Handler自身的hanldeMessage方法,该方法默认是个空方法,咱们须要本身是重写实现该方法。
综上,咱们能够看到Handler提供了三种途径处理Message,并且处理有先后优先级之分:首先尝试让postXXX中传递的Runnable执行,其次尝试让Handler构造函数中传入的Callback的handleMessage方法处理,最后才是让Handler自身的handleMessage方法处理Message。
让咱们看一下handleMessage(msg)
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
复制代码
能够看到这是一个空方法,为何呢,由于消息的最终回调是由咱们控制的,咱们在建立handler的时候都是复写handleMessage方法,而后根据msg.what进行消息处理。
private Handler mHandler = new Handler(){
public void handleMessage(android.os.Message msg){
switch (msg.what){
case value:
break;
default:
break;
}
};
};
复制代码
到此,sendMessage方式流程已经解释完毕,接下来看下post方式。
mHandler.post(new Runnable()
{
@Override
public void run()
{
Log.e("TAG", Thread.currentThread().getName());
mTxt.setText("yoxi");
}
});
复制代码
而后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;
}
复制代码
能够看到,在getPostMessage中,获得了一个Message对象,而后将咱们建立的Runable对象做为callback属性,赋值给了此message。 注:产生一个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。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
复制代码
能够看到,这里msg的callback和target都有值,那么会执行msg.callback != null的判断,则执行handleCallback回调,也就是咱们的Runnable对象。
到此,这个流程已经解释完毕,让咱们首先总结一下:
首先Looper.prepare()在本线程中保存一个Looper实例,而后该实例中保存一个MessageQueue对象;由于Looper.prepare()在一个线程中只能调用一次,因此MessageQueue在一个线程中只会存在一个。
在Lopper构造函数中,建立了一个消息队列MessageQueue,并将其赋值给其成员字段mQueue,这样Looper也就与MessageQueue经过成员字段mQueue进行了关联。
Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,而后回调msg.target.dispatchMessage(msg)方法。
Handler的构造方法,会首先获得当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
Handler的sendMessage方法,会给msg的target赋值为handler自身,而后加入MessageQueue中。
在构造Handler实例时,咱们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。
咱们在本文讨论了Thread、MessageQueue、Looper以及Hanlder的之间的关系,咱们能够经过以下一张传送带的图来更形象的理解他们之间的关系。
咱们能够把传送带上的货物看作是一个个的Message,而承载这些货物的传送带就是装载Message的消息队列MessageQueue。传送带是靠发送机滚轮带动起来转动的,咱们能够把发送机滚轮看作是Looper,而发动机的转动是须要电源的,咱们能够把电源看作是线程Thread,全部的消息循环的一切操做都是基于某个线程的。一切准备就绪,咱们只须要按下电源开关发动机就会转动起来,这个开关就是Looper的loop方法,当咱们按下开关的时候,咱们就至关于执行了Looper的loop方法,此时Looper就会驱动着消息队列循环起来。
那Hanlder在传送带模型中至关于什么呢?咱们能够将Handler看作是放入货物以及取走货物的管道:货物从一端顺着管道划入传送带,货物又从另外一端顺着管道划出传送带。咱们在传送带的一端放入货物的操做就至关于咱们调用了Handler的sendMessageXXX、sendEmptyMessageXXX或postXXX方法,这就把Message对象放入到了消息队列MessageQueue中了。当货物从传送带的另外一端顺着管道划出时,咱们就至关于调用了Hanlder的dispatchMessage方法,最终执行handleMessage方法,在该方法中咱们完成对Message的处理。