Looper作为轮询器,其作用就像送货员的货运车,用于为指定线程创建并维护一个消息队列,并从消息队列中取出消息,交给Handler处理。
1. Looper中的一些字段
private static final String TAG = "Looper";
// sThreadLocal.get() will return null unless you've called prepare().
//ThreadLocal保存着各个线程的信息,但当前线程调用的时候又只会得到当前线程信息,这里是创建的保存Looper对象的ThreadLocal对象
static final ThreadLocal sThreadLocal = new ThreadLocal();
private static Looper sMainLooper; // 主线程的Looper对象引用
final MessageQueue mQueue; //与该Looper绑定的MessageQueue字段
final Thread mThread; //与该Looper绑定的线程
private Printer mLogging; //打印Log的
private long mTraceTag; //追踪标记
2. 创建Looper对象,prepare()方法
我们在创建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));
}
这个方法是私有的,首先使用ThreadLocal中的get()方法,这个方法可以得到当前线程的Looper对象,如果不为空则会抛出异常,为空则创建新的对象,所以这个方法明确了** 一个线程只能创建一个Looper. **
ThreadLocal为每个线程单独保存了一份信息,多线程下可以同时访问,但是又互不影响,有兴趣的可以去看看ThreadLocal源码,里面的代码不多.这里就不展开说明了.
接着我们来看看quitAllowed这个参数,意思很明确,是否允许退出,刚才传进来的参数为true,那么就表示允许退出,那退出什么呢?,可以看到它又将这个传到给了其构造方法,那我们接下来就来看看其构造方法.
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
这个方法也是私有的,所以我们不能用** new ** 创建Looper对象,这个方法就做了两件事.
- 将创建MessageQueue对象并将quitAllowed传给它.
- 得到当前对象,并赋给mThread字段.
这里简单来说就是在创建Looper对象的时候,绑定了一个消息队列和当前线程.
既然将quitAllowed传到了MessageQueue中,那我们来简单看看这个在MessageQueue中做了什么吧.
** MessageQueue.class **
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
可以看到这个构造方法也是就做了两件事.
- 先将其赋给了MessageQueue中的mQuitAllowed字段.
- 调用了native层中的nativeInit方法.
这个方法是用C++写的,有兴趣的可以去看看,这个方法主要就是在native层创建了一个MessageQueue,然后mPtr就是指向native层中MessageQueue中的指针.
实际上MessageQueue真正的创建也就是在native层中,使用C++来写的,采用的ePoll和Poll机制来进行消息驱动,毕竟这些操作还是用C++来完成比较有效率.
这里只是将quitAllowed赋给了mQuitAllowed ,没有看到其具体的作用,既然如此,那我们继续找找.
就是这了
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
先找到mQuitAllowed,可以看到quit方法中的采参数就是mQuitAllowed,当其为true才可以继续下面的代码,否则就会抛出异常了,
接下来不看其他的,可以看到总共就只有3个方法.
-
removeAllFutureMessagesLocked();
和removeAllMessagesLocked();
看名字很明显是用来移除消息的,和safe参数有关,所以将这两者放在一起,显而易见,safe为true就调用前者,为false就调用后者,那么这两者有什么区别呢?我们还是看名字,一个是feature,一个是all,那么我们可以猜测,一个是移除未来,也就是还没执行的消息,一个是不管其他,移除全部的消息.嘛实际这两个方法也就是这个作用...关于MessageQueue源码,下次再仔细说... - 最后还有个方法
nativeWake(mPtr)
看名字就知道是调用的native层的方法,那么这个方法是干嘛用的呢?在这之前先想想,在执行这个方法之前做了什么?对,就是移出消息,不管是调用的是移除未执行的还是移除全部的,** 都产生了一个结果,MessageQueue中的消息发生了变化 ** 那么显而易见的,这个方法的作用就是唤醒native中的MessageQueue来进行真正的移除操作.你看都不需要去看native层中C++的代码,就能明白其方法的具体作用了~!
那么言归正传,还记得么quit方法中mQuitAllowed如果为false,会怎样?对,抛出异常,那还记得抛出的是什么异常么?对,就是** Main thread not allowed to quit **主线程不允许退出,那么也就是主线程也会创建Looper对象,而且传进来的mQuitAllowed参数为false((这不是废话么~!)).
再回到** Looper **之前我们先去看看主线程到底在哪里创建了Looper对象.
大家是否还记得在java中我们的程序都是从main方法开始执行的,可是到了Android中并没有看到main方法,会不会曾经产生过这样的疑问,是不是Android中没有main方法?Android不也是java写的么,为什么差别会这么大呢?实际上不是的.让我们看看下面这个类
** ActivityThread.class **
public static void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
......
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
可以看到在ActivityThread里面有个main方法,这里就是java层的起始了,为什么说是java层呢?当然是还有个native层(这不废话么),让我们看看这个方法,这里面我只截取了部分代码,具体的可以去看看源码,
这有这么一句代码Looper.prepareMainLooper();
还有这一句 Looper.loop();
很明显,这两句代码的作用一个就是创建主线程的Looper对象,另一个就是进行轮询消息了.
在这两个方法间还有个sMainThreadHandler = thread.getHandler();
得到一个Handler,既然Thread,Looper,MessageQueue都有了,那么Handler当然也不能少.
最后的最后,也就是在main()方法的最后,还抛出个异常,这是干嘛呢?还能干嘛,异常信息写的很清楚** 主线程循环意外退出了 **正常情况下是执行不到这一句代码的.
对了,ActivityThread并不是主线程,只是一直运行在主线程上而已,主线程是Zygote创建的.
那最后让我来看看main()方法调用的Looper.prepareMainLooper()
吧,终于回到Looper中了~!
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
可以看到prepareMainLooper()
这个方法其实和prepare()
差不多,myLooper()
其内部也只是return sThreadLocal.get()
而已,所以就不在多说了.
只是一个Looper的创建就扯了这么久,(我还是真能水啊,呵呵),嘛,毕竟Looper牵涉的比较多,又是MessageQueue又是ActivityThread的,还聊了些之外的MessageQueue中quit和nativeWake.
3. Looper中quit方法
既然都已经提到了MessageQueue中quit方法,那么接下就说说Looper中的quit方法吧,大家估计猜都猜到里面肯定调用了MessageQueue中的quit方法,既然如此,那么就不用说了吧.嘛,实际上Looper这个quit方法里面还真就是只调用了MessageQueue中quit方法,发个源码看看就行了.
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
就是一个是安全退出,一个是不安全退出,都调用的MessageQueue中的quit方法.
接下来就是重头戏了
4. Looper中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;
.......
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
.......
try {
msg.target.dispatchMessage(msg);
}
......
msg.recycleUnchecked();
}
}
这个方法不算太长,但也不短,所以我删减了一些不太重要的,身份验证,trace和一些Log,详情可以去看看源码.
首先这是myLooper();
里的具体实现return sThreadLocal.get()
返回的就是当前线程的Looper.
那么这个方法基本可以分为四部分:
-
for(;;)
之前,就是得到当前线程的Looper对象和与其绑定的MessageQueue对象. - 调用MessageQueue中的
Message msg = queue.next()
方法,拿到消息. - 调用Message中的
msg.target.dispatchMessage(msg)
方法,执行消息 - 执行
msg.recycleUnchecked()
回收消息.
在loop()中主要的其实就是执行消息和回收消息,至于拿到消息的具体实现在MessageQueue中,这个下次再说.
以上就是Looper中和消息处理机制有关,并且比较重要的方法了.至于其他的一下方法,可以去阅读阅读一下源码,多看看一些源码还是对提升挺有帮助的.
** 总结: **
- Looper里面有着MessageQueue和当前线程thread的字段,并且Looper对象是存放在ThreadLocal中的
- 创建Looper对象的时候会绑定当前线程和创建一个MessageQueue对象,并与之绑定.主线程的Looper对象在ActivityThead中的main()被创建,
- 主线程的quitAllowed为false,不可退出.其他线程的quitAllowed为true.可以退出.
- loop()是真正进行消息轮询的地方,里面是个死循环,主要做的事为,调用MessageQueue中的
next()
拿到消息,然后处理消息,最后将消息回收.
相关文章:
Handler机制源码分析之Handler
Handler机制源码分析之Message
参考文章:
Android消息处理机制(Handler、Looper、MessageQueue与Message)
Android消息机制2-Handler(Native层)