Handler可以帮助我们在特定的线程执行任务。我们也可以用Handler计划一个任务在未来某个时间点执行。Handler会将我们给它的任务在特定的线程里进行排队执行。如果我们想在某个线程做些什么任务,我们可以指定Handler的Looper,然后Handler就会将这个任务添加到Looper对应的消息队列(message queue)。
val handler = Handler(Looper.getMainLooper())
val runnable = Runnable {
println("Hello world")
}
handler.postDelayed(runnable,3_000L)
创建Looper
我们在某个线程里调用Looper.prepare()
,就会给这个线程创建一个Message Queue
。
Looper.getMainLooper()
的有关的代码:
这是应用在启动时,调用的main函数。main函数写在哪里是无所谓的,在计算机操作系统里已约定好程序的入口是main,所以你也会看到它是static的。android的应用程序的main函数都写在ActivityThread.java这个文件里。下面是启用启动时准备主线程使用的Looper:
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
}
prepareMainLooper()
函数:
看到未!它调用了prepare()函数。为当前线程准备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();
}
}
prepare()
函数:
为当前线程(主线程)创建一个Looper,因为是主线程,所以quitAllowed要传false。否则Message Queue里的消息就会有被销毁的风险。
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));
}
创建Looper的同时会当前线程创建一个MessageQueue:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
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);
}
}
创建好的Looper会被保存起来:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
prepare()函数调用完成后Looper创建工作就完成了,调用myLooper()
就是去将这个Looper拿回来赋给sMainLooper,Looper.getMainLooper()拿到的就是这个值:
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
到此应用启动后马上为主线程创建好了一个Looper了,通过Looper.getMainLooper()
就可以拿到这个主线程的Looper。
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
顺便提一下,Looper创建出来的MessageQueue是一个链表,它的元素是Message:
public final class MessageQueue {
@UnsupportedAppUsage
Message mMessages;
...
@UnsupportedAppUsage
Message next() {
...
for (;;) {
...
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
...
} else {
// Got a message.
...
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
...
msg.markInUse();
return msg;
}
}
...
}
}
}
}
Handler与Looper的关系
我们拿到了主线程的Looper传给Handler有什么用呢?首先,Handler是android.os
包里一个普通的类。
我们创建一个Handler实例,这个实例引用着主线程的Looper:
val handler = Handler(Looper.getMainLooper())
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
通过对主线程Looper的引用,Handler也引用着主线程Looper的MessageQueue:
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
Handler怎么使用Looper呢?我以上面为例来说明:
handler.postDelayed(runnable,3_000L)
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
getPostMessage()将我们的任务(任务都是用Runnable来写的)生成一个Message:
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
Message.obtain()会先偿试从消息池找一个,如没有就创建一个新的。消息池是一个链表:
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
我们的任务是放在Message的callback字段上的,而Message的target将要放的是我们的Handler对象,请往下继续阅读:
Message{
...
@UnsupportedAppUsage
/*package*/ Runnable callback;
@UnsupportedAppUsage
/*package*/ Handler target;
...
}
sendMessageAtTime()函数,这是一个过渡,做些准备:
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
Handler拿出Looper的MessageQueue,准备做最后的消息入队操作:
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);
}
Handler对象将自己的引用给了创建出来的Message对象的target字段,然后,通过Looper对象的MessageQueue对象将Message送入队列:
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
至此Handler已完成了它的工作了,那么Looper的MessageQueue里的Message消息什么时候会被取出来操作呢?
Message的执行
main函数最后面有这么一行Looper.loop();
,使android应用程序不会退出,因此它会一直循环下去。否则main函数就会被结束。
public static void main(String[] args) {
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
loop()函数会拿出当前线程的Looper,比如当前线程是主线程,那么myLooper()拿回来的就是主线程的Looper()
public static void loop() {
final Looper me = myLooper();
...
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
从当前线程的Looper的MessageQueue取出一个Message,然后把Message给Message的target字段记录的Handler对象处理:
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
...
try {
msg.target.dispatchMessage(msg);
...
}
...
return true;
}
Handler的dispatchMessage()方法,如果callback不是null就是去执行,callback记录的是我们的任务:
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();
}
如果msg.callback是null,且在创建Handler对象时有传个callback的话,就会先调用这个callback再调用handleMessage()
方法:
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async)
public void handleMessage(@NonNull Message msg) {
}
handleMessage()
是一个空方法,所在此方面的实践,往往需要我们重写它,例子:
val handler = object: Handler(Looper.getMainLooper()){
override fun handleMessage(msg: Message) {
println("Hello world")
}
}
val msg = Message.obtain()
handler.sendMessage(msg)
到此我们知道,任务在哪个线程执行的关键就是prepare()在哪里被执行,也就是为哪个线程创建Looper,发送到这个Looper的任务就会在相应的线程里执行。
runOnUiThread到底做了什么?
class Activity ... {
...
final Handler mHandler = new Handler();
...
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
}
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
Activity实例创建时,也会构造一个Handler实例,runOnUiThread()
就是利用这个Handler实例向主线程的Looper发现任务。
Handler的知识大体是这样,更多其他涉及的知识,我们以后再分享啦。