Thread
并不是天然具有消息处理机制的,为了给
Thread
赋予消息处理机制,Android为引入了
Looper
.
Looper
的
Thread
中,这几个类的关系为:
Thread
有一个Looper
(一对一)Looper
中有一个MessageQueue
(一对一)Looper
不停的从MessageQueue
中取出消息并通过Handler进行处理在Looper.java
中,有这样一段关于Looper
的介绍。只要在Thread
的run()
中调用Looper.prepare()
可以给Thread
添加一个Looper
对象,调用Looper.loop()
可以让刚刚创建的Looper
对象进入循环,不断取出消息并通过Handler
进行处理。
frameworks/base/core/java/android/os/Looper.java
/**
* Class used to run a message loop for a thread. Threads by default do
* not have a message loop associated with them; to create one, call
* {@link #prepare} in the thread that is to run the loop, and then
* {@link #loop} to have it process messages until the loop is stopped.
*
* <p>Most interaction with a message loop is through the
* {@link Handler} class.
*
* <p>This is a typical example of the implementation of a Looper thread,
* using the separation of {@link #prepare} and {@link #loop} to create an
* initial Handler to communicate with the Looper.
*
* <pre>
* class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler(Looper.myLooper()) {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }</pre>
*/
Looper.prepare()
实现实际上Looper.prepare()
做的事情非常简单,它就是新建了一个Looper对象并"赋值"给了线程私有变量,sThreadLocal
。
frameworks/base/core/java/android/os/Looper.java
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
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));
}
sThreadLocal
的实现非常简单,可以理解为它内置了一个Map
,key
是Thread
对象,value
则是线程私有的变量。所以对他进行"赋值"时,要使用set
方法而不是"="。
Looper
中的MessageQueue
和Looper.loop()
Looper中有一个MessageQueue对象mQueue.
frameworks/base/core/java/android/os/Looper.java
@UnsupportedAppUsage
final MessageQueue mQueue;
frameworks/base/core/java/android/os/Looper.java
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
@SuppressWarnings({"UnusedTokenOfOriginalCallingIdentity",
"ClearIdentityCallNotFollowedByTryFinally",
"ResultOfClearIdentityCallNotStoredInVariable"})
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true; //标记当前线程已在loop循环当中
// 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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", -1);
me.mSlowDeliveryDetected = false;
for (;;) {
//不断调用loopOnce处理消息
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
frameworks/base/core/java/android/os/Looper.java
/**
* Poll and deliver single message, return true if the outer loop should continue.
*/
@SuppressWarnings({"UnusedTokenOfOriginalCallingIdentity",
"ClearIdentityCallNotFollowedByTryFinally"})
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
// 从mQueue中取出下一个消息,线程有可能在此阻塞。
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
...
try {
//调用msg.target.dispatchMessage处理消息。实际上就是通过Handler来处理消息。
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
return true;
}
msg.target
实际上就是一个Handler
对象
frameworks/base/core/java/android/os/Message.java
@UnsupportedAppUsage
/*package*/ Handler target;
Handler
发送和处理消息我们这里只需要关心mLooper
, mQueue
和 mCallback
。
之前说过,Handler
只是用来处理消息,从MessageQueue
中取出消息并调用Handler
进行处理是在Looper
中进行的。所以在new
一个Handler
对象的时候,需要给他指定一个Looper
,这个Looper
会调用新建的Handler
处理消息。通过Handler
发送的消息,会添加到mQueue
队列中,并通过mLooper
不断取出再调用Handler
进行处理。
frameworks/base/core/java/android/os/Handler.java
/** @hide */
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async,
boolean shared) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
mIsShared = shared;
}
mCallback
则是用来处理消息的关键,我们在日常使用中,一般是通过如下方式处理消息:
Handler.Callback
Handler
的mCallback
Handler
会调用mCallback
的handleMessage
方法处理消息。frameworks/base/core/java/android/os/Handler.java
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*/
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
Handler
发送消息通过Handler
发送消息最终会调用到sendMessageAtTime
,它会调用enqueueMessage
将消息加入mQueue
(也就是mLooper
的mQueue
)。
frameworks/base/core/java/android/os/Handler.java
public boolean sendMessageAtTime(@NonNull 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);
}
我们看到,在enqueueMessage
中会将msg.target
设置为当前的Handler
。前面说过,Looper
会调用 msg.target.dispatchMessage
处理消息,这也就保证了,发送和处理消息的Handler
是同一个。
frameworks/base/core/java/android/os/Handler.java
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;//将msg.target设置为当前的Handler对象
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler
处理消息在dispatchMessage
处理消息的流程中,有三种处理方式
message
中携带了Runnable
对象,那么就调用他的run()
方法Runnable
对象,并且mCallback
不为空,那么调用mCallback
进行处理Handler
自身的HandleMessage
进行处理。frameworks/base/core/java/android/os/Handler.java
public void dispatchMessage(@NonNull 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();
}
Handler
的handleMessage
本身是没有处理逻辑的,如果想要使用Handler.handleMessage
进行处理,则需要新建Handler
的子类并重写handleMessage
方法。
frameworks/base/core/java/android/os/Handler.java
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}