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.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);elsecreateMap(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 {@UnsupportedAppUsageMessage mMessages;...@UnsupportedAppUsageMessage 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;}} ...}}}
}
我们拿到了主线程的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 flagsPoolSize--;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消息什么时候会被取出来操作呢?
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的任务就会在相应的线程里执行。
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的知识大体是这样,更多其他涉及的知识,我们以后再分享啦。