Android消息机制源码解析(三)——消息循环器Looper
2015-12-14 20:23
459 查看
本节来分析Looper,Looper可以理解为一个消息循环器,不断从消息队列中取出消息,然后交给Handler处理。如果一个线程中有多个Handler,则会根据Message的target属性来将消息处理任务分发到特定的Handler。如果消息队列中没有消息了,那么Looper就会等待,直到有消息进来,下面看一下Looper的源码实现。
一、Looper类的定义如下
public final class Looper
可以看到Looper类被定义为final类型,则此类不可以被继承。
Looper主要属性字段:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
这里涉及到一个叫ThreadLocal的东西,ThreadLocal的作用简单说就是可以在多个线程中被共享,但是在ThreadLocal中却可以保存各个线程的值,在不同线程中访问时,返回的也是不同线程保存的值,其实现源码也比较简单,有兴趣的同学可以自己看一下。ThreadLocal很有用,在Looper中,sThreadLocal用来保存每个线程的Looper对象,同时也可以从中取出各个线程的Looper。sMainLooper表示主线程的Looper对象;mQueue表示消息队列;mThread表示当前线程。
二、接下来分析如何初始化一个Looper,答案是通过prepare()方法:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
注意上述代码中的异常提示“Only one Looper may be created per thread”,它告诉我们,每个线程只能有一个Looper,通过sThreadLocal的set()和get()可以设置与获取到当前线程的Looper。再看下Looper的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
其中布尔型的参数表示该Looper是否可以退出,此值会传到MessageQueue中,后面一节会讲到。上述代码实际上给Looper绑定了一个MessageQueue和Thread,既然一个线程只有一个Looper,也就只有一个MessageQueue。
三、之前提到在主线程创建Handler时不需要手动创建Looper,那么主线程的Looper又是如何被创建的呢?先看如下的方法:
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/** Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
prepareMainLooper()就是为主线程创建Looper,此函数就是在主线程ActivityThread中被调用的;getMainLooper()则可以返回主线程的Looper对象。
四、Looper还提供了一些其他方法:
public static Looper myLooper() {
return sThreadLocal.get();
}
上述方法返回当前线程的Looper。
public static MessageQueue myQueue() {
return myLooper().mQueue;
}
上述方法返回当前线程的Looper对应的消息队列。
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
上述方法用来判断当前线程是否为Looper所在的线程。
public boolean isIdling() {
return mQueue.isIdling();
}
上述方法用来判断此Looper是否处于闲置状态,其本质是判断MessageQueue是否处于闲置状态。
五、通过以上源码分析,大家已经了解如何创建一个Looper了,那么Looper创建好之后,是怎么运转的呢,它是怎样从消息队列不断获取消息的呢?下面请出Looper最重要的loop()方法:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
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.recycleUnchecked();
}
}
首先拿到当前线程的Looper,再得到该Looper对应的MessageQueue;接下来Binder相关的两句是关于进程间通信的,不影响我们理解。最重要的逻辑在for循环里,这是一个无限循环,首先从消息队列取消息:
Message msg = queue.next(); // might block
注意后边的注释语句,next()的具体实现会在下一节MessageQueue中介绍,这个方法可能会阻塞,理解这一点非常重要,阻塞说明即会等待,当有消息时就会被唤醒,而等待时并不会消耗太多资源,所以并不会造成卡死。接下里的if语句说明跳出循环的唯一条件是msg为null,接下来会提到的Looper的quit()方法,其实质就是调用MessageQueue的quit(),让next()返回null,这样Looper就会跳出循环了。如果Looper从消息队列中获取的消息不为null,则分发给此消息对应的Handler处理:
msg.target.dispatchMessage(msg);
Handler的dispatchMessage(Message msg)就是在这个地方调用的。最后一行代码是Message对象的回收。需要提醒一下,创建Looper之后,必须调用其loop(),才能将其启动起来。
六、最后是Looper的退出方法,有两个:
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
可以看到都是调用了MessageQueue的退出方法,它们的区别时,直接退出则loop()不再处理任何消息马上终止,而安全退出时loop()会执行完目前已经在处理的消息,之后才终止。
Looper的主要源码已经分析完了,需要明白的是一个线程只有一个Looper、一个MessageQueue,但可以有多个Handler。最后一节《Android消息机制源码解析——消息队列MessageQueue》将分析Android消息机制的最后一部分内容。
一、Looper类的定义如下
public final class Looper
可以看到Looper类被定义为final类型,则此类不可以被继承。
Looper主要属性字段:
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
这里涉及到一个叫ThreadLocal的东西,ThreadLocal的作用简单说就是可以在多个线程中被共享,但是在ThreadLocal中却可以保存各个线程的值,在不同线程中访问时,返回的也是不同线程保存的值,其实现源码也比较简单,有兴趣的同学可以自己看一下。ThreadLocal很有用,在Looper中,sThreadLocal用来保存每个线程的Looper对象,同时也可以从中取出各个线程的Looper。sMainLooper表示主线程的Looper对象;mQueue表示消息队列;mThread表示当前线程。
二、接下来分析如何初始化一个Looper,答案是通过prepare()方法:
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
注意上述代码中的异常提示“Only one Looper may be created per thread”,它告诉我们,每个线程只能有一个Looper,通过sThreadLocal的set()和get()可以设置与获取到当前线程的Looper。再看下Looper的构造函数:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
其中布尔型的参数表示该Looper是否可以退出,此值会传到MessageQueue中,后面一节会讲到。上述代码实际上给Looper绑定了一个MessageQueue和Thread,既然一个线程只有一个Looper,也就只有一个MessageQueue。
三、之前提到在主线程创建Handler时不需要手动创建Looper,那么主线程的Looper又是如何被创建的呢?先看如下的方法:
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/** Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
prepareMainLooper()就是为主线程创建Looper,此函数就是在主线程ActivityThread中被调用的;getMainLooper()则可以返回主线程的Looper对象。
四、Looper还提供了一些其他方法:
public static Looper myLooper() {
return sThreadLocal.get();
}
上述方法返回当前线程的Looper。
public static MessageQueue myQueue() {
return myLooper().mQueue;
}
上述方法返回当前线程的Looper对应的消息队列。
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
上述方法用来判断当前线程是否为Looper所在的线程。
public boolean isIdling() {
return mQueue.isIdling();
}
上述方法用来判断此Looper是否处于闲置状态,其本质是判断MessageQueue是否处于闲置状态。
五、通过以上源码分析,大家已经了解如何创建一个Looper了,那么Looper创建好之后,是怎么运转的呢,它是怎样从消息队列不断获取消息的呢?下面请出Looper最重要的loop()方法:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
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.recycleUnchecked();
}
}
首先拿到当前线程的Looper,再得到该Looper对应的MessageQueue;接下来Binder相关的两句是关于进程间通信的,不影响我们理解。最重要的逻辑在for循环里,这是一个无限循环,首先从消息队列取消息:
Message msg = queue.next(); // might block
注意后边的注释语句,next()的具体实现会在下一节MessageQueue中介绍,这个方法可能会阻塞,理解这一点非常重要,阻塞说明即会等待,当有消息时就会被唤醒,而等待时并不会消耗太多资源,所以并不会造成卡死。接下里的if语句说明跳出循环的唯一条件是msg为null,接下来会提到的Looper的quit()方法,其实质就是调用MessageQueue的quit(),让next()返回null,这样Looper就会跳出循环了。如果Looper从消息队列中获取的消息不为null,则分发给此消息对应的Handler处理:
msg.target.dispatchMessage(msg);
Handler的dispatchMessage(Message msg)就是在这个地方调用的。最后一行代码是Message对象的回收。需要提醒一下,创建Looper之后,必须调用其loop(),才能将其启动起来。
六、最后是Looper的退出方法,有两个:
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
可以看到都是调用了MessageQueue的退出方法,它们的区别时,直接退出则loop()不再处理任何消息马上终止,而安全退出时loop()会执行完目前已经在处理的消息,之后才终止。
Looper的主要源码已经分析完了,需要明白的是一个线程只有一个Looper、一个MessageQueue,但可以有多个Handler。最后一节《Android消息机制源码解析——消息队列MessageQueue》将分析Android消息机制的最后一部分内容。
相关文章推荐
- js继承 Base类的源码解析
- android的消息处理机制(图文+源码分析)―Looper/Handler/Message
- Android中的Looper对象详细介绍
- Android消息处理机制Looper和Handler详解
- AsyncTask陷阱之:Handler,Looper与MessageQueue的详解
- Looper类浅析
- Android的线程使用来更新UI----Thread、Handler、Looper、Time...
- Handler Looper MessageQueue总结
- android:fitSystemWindows详解
- android:fitSystemWindows详解
- Android多线程Handler的使用,基于源代码理解。
- Android之Looper+Thread+handler
- 单线程模型中Message、Handler、Message Queue、Looper之间的关系。
- 如此抄袭Apps之OscHub(三)
- Android的Looper和Handler消息处理机制详解
- Android笔记——Handler
- Android消息循环
- Handler异步消息处理机制浅析
- Android异步处理机制ActivityThread+Looper+Handler的深入分析
- SDWebImage源码分析