Looper
上篇介绍的是 Message
和 MessageQueue
,有了传递的消息和负责存储的队列,接下来看看负责调度的 looper
Class used to run a message loop for a thread
看一下 looper
中的属性:
//只有调用了prepare方法之后,sThreadLocal.get()才不会返回空
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class 主线程中的Looper
final MessageQueue mQueue;//与之管理的消息队列
final Thread mThread;//当前线程
private Printer mLogging;
private long mTraceTag;
private long mSlowDispatchThresholdMs;
从 looper
中的注释可以知道,线程默认是没有 looper
,需要调用 Looper.prepare()
为当前线程创建一个 looper
,接着调用 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();
}
上面提到了两个主要的方法:Looper.prepare();
和 Looper.loop();
首先看一下 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));
}
通过上面的代码可以知道,prepare
方法主要就是往 sThreadLocal
中存放一个 looper
对象,由于 ThreadLocal
的特性可以知道,一个线程中只能有一个 looper
对象,因为ThreadLocal
是线程中共享的,如果重复调用prepare的话,就会报错。
看到 prepare
方法,不得不说说 prepareMainLooper
:
/**
* 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();
}
}
prepareMainLooper
这个方法主要是在 ActivityThread
中的 main
方法中被调用的,而 ActivityThread
线程就是我们所说的主线程了,通过注释我们可以看出这个方法这个 mainLooper
在Android环境中是为了 application
创建的,这个方法永远都不需要我们手动去调用。
再看构造方法,里面只有两行代码:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
创建了消息队列,并获取了当前线程 。
到这里 prepareMainLooper()
就执行完了,查看 prepareMainLooper()
调用者可以看到,在 SystemServer.run()
与 ActivityThread.main()
中都在调用 Looper.prepareMainLooper()
后不远就调用了 Looper.loop()
。而这两处可以推断一个是系统应用的主线程,一个是用户应用的主线程。
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;
// 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 这个方法是会阻塞的,知道拿到Message,或者退出队列
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
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
final long traceTag = me.mTraceTag;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
final long end;
try {
//调用了message的target进行分发处理事件,target其实就是跟message绑定的handler
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (slowDispatchThresholdMs > 0) {
final long time = end - start;
if (time > slowDispatchThresholdMs) {
Slog.w(TAG, "Dispatch took " + time + "ms on "
+ Thread.currentThread().getName() + ", h=" +
msg.target + " cb=" + msg.callback + " msg=" + msg.what);
}
}
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.loop()
也很简单,就是调用 MessageQueue.next()
方法取消息,如果没有消息的话会阻塞,直到有新的消息进入或者消息队列退出。
拿到消息后调用消息关联的 Handler
处理消息。
可以看到,Looper
并没有执行消息,真正执行消息的还是添加消息到队列中的那个 Handler
,真应了那句:解铃还须系铃人啊!
在 looper
的构造方法中我们可以看到一个参数 quitAllowed
为是否允许退出,最后是将这个参数给 MessageQueue
,可以猜测到,looper
中的退出方法应该是调用了 MessageQueue
的退出方法,来看一下代码:
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
两个方法都是结束,那这两个方法之间的区别是什么呢,等我给你慢慢道来:还是先看源码吧
void quit(boolean safe) {
if (!mQuitAllowed) {
//只有主线程的mQuitAllowed才会为false,如果代码能够进到这里面,说明退出的是主线程的looper
//主线程的looper是不需要也是不允许手动停止的
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);
}
}
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) {//挨个遍历,把消息全都回收
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {//消息链表不为空
if (p.when > now) {//链表中的消息执行时间都要比当前时间晚,则挨个移除消息
removeAllMessagesLocked();
} else {
Message n;
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
移除消息的逻辑就是先判断当前的 Looper
是否为主线程的 Looper
,如果是的话就直接报错,主线程的 Looper
是不运行手动退出的。接下来就是判断当前的 Looper
是否已经退出了,如果已经退出了就直接返回,否则的话就进行消息移除逻辑,如果是不安全的移除的话,那就是直接移除队列中所有的消息。如果是安全移除的话,首先会判断当前的队列中是否有消息,然后判断当前的队头消息的时间是不是比当前时间要晚,如果要晚的话就直接移除所有消息。如果不是的话,斗图模式开启,首先看一下执行代码 n = p.next;
以后的效果:
如果没有下一个 message
为空的时候,也就是说没有队列中只有一个消息了,那就直接返回并让消息执行。下一个消息不为空的话就会继续判断,消息n的执行时间是否大于当前时间,如果不是的话就执行 p = n;
:
并且继续轮询,如果想要继续执行下面代码的话,那只有满足条件 n.when > now
,这个时候就会执行代码 p.next = null;
:
然后继续执行代码 p = n;
执行 n = p.next;
后,链表的结构会跟最初的状态一样,如果消息n不为空的话,就会继续执行并回收消息,直到消息为空。轮询结束。
两种停止轮询的方法主要区别在于:一个是不管三七二十一,直接移除所有消息;一个是让立马需要执行的消息先执行完毕,然后在移除队列中需要等待执行的消息。
Handler
上主菜,但是是一个很简单的主菜,为什么呢,因为 Handler
好多的操作都交给了 MessageQueue
和 Looper
去处理了,Handler
只要调用方法就行了。
首先看一下 Handler
的构造方法,来深入了解一下:
public Handler(Callback callback, boolean async) {
...
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;
}
在当前线程中创建 Handler
的时候会判断当前线程是否创建过 Looper
,也就是是否先调用了 Looper.prepare();
方法,如果没有调用的话就会报错。然后就是给成员变量赋值。
接下来看一下发送消息的方法
一般来说分为两种
post(Runnable r)
sendMessage(Message msg)
先看一下 post(Runnable r)
方法
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis){
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {;
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
原来 post
方法其实是调用的是 sendMessageAtTime
方法,只是将 Runnable
进行封装到了 Message
中。那我们再看看sendMessage(Message msg)
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
也是调用 sendMessageDelayed
方法,那我们只需要关注 sendMessageAtTime
方法就行了。
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);
}
首先会判断 mQueue
是否为空,如果为空则直接抛出异常并返回,否则的话继续调用 enqueueMessage
,将当前的 Handler
对象设置给 msg
,最后调用了 MessageQueue
的 enqueueMessage
方法加入到队列中。
处理消息
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
首先会判断 msg
对象中的 callback
属性是否为空,那么 callback
是在什么时候放到 Message
中的呢?其实就是我们调用 post(Runnable r)
方法的时候,就会将这个 Runnable
赋值给 Message.callbck
的,如果 callback
不为空的话,就会执行在当前线程执行 run 方法。如果为空的话,也就是我们发送消息的时候是采用 sendMessage(Message msg)
方式进行发送的,接下来我们看到了 mCallback
,这个是什么呢,什么时候赋值的呢?
public Handler(Callback callback) {
this(callback, false);
}
咦?是构造方法?我细细想...
Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
return false;
}
});
是的,没错了,应该就是这样的,如果我们这样创建一个 Handler
的话,mCallback
属性就不会为空,如果 mCallback.handleMessage(msg)
返回为 ture
的话,就不会继续走,直接就返回了。如果 mCallback
为空或者是 mCallback.handleMessage(msg)
为 false
,就会调用到 handleMessage
方法,handleMessage
方法在 Handler
其实是一个空实现,需要在子类中进行重写。处理消息的逻辑基本到此就结束了。
移除消息
public final void removeMessages(int what, Object object) {
mQueue.removeMessages(this, what, object);
}
public final void removeCallbacks(Runnable r)
{
mQueue.removeMessages(this, r, null);
}
可以看见,其实 Handler
什么都没有做,只是单纯的调用了 MessageQueue
中的方法, MessageQueue
的移除方法在之前已经讲解过了,就不进行再次讲解了。