handler创建过程
1.当我们创建一个handler时,会调用Looper.myLooper()从threadlocal中获取一个looper对象(ThreadLocal的知识点 )
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
这里如果获取不到looper对象会抛出异常,主线程(ActivityThread)已经为我们初始化了looper,如果在子线程创建handler则需要手动调用Looper.prepare()来初始化looper对象到ThreadLocal中,并且该方法同一个线程只能调用一次。
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));
}
2.子线程中创建handler
- 在子线程中创建handler,在子线程中处理 messge
thread {
Looper.prepare()
Handler {
println(Thread.currentThread().name)
true
}.sendEmptyMessage(0)
Looper.loop()
}
- 在子线程创建handler, 在主线程处理messge
thread {
val looper = Looper.getMainLooper()
Handler(looper) {
println(Thread.currentThread().name + "----$it")
true
}.apply {
(0..10).forEach {
sendEmptyMessage(it)
}
}
}
- 使用HandlerThread,类似第一个
/**
* handler thread 在一个名为work的线程中顺序处理消息
*/
fun test3(){
val thread = HandlerThread("work").apply { start() }
Handler(thread.looper){
println(Thread.currentThread().name + "----${it.what}")
true
}.apply {
(0..10).forEach {
sendEmptyMessage(it)
}
}
}
关于Looper
对一个handler来说looper对象是必不可少的
1.Looper是什么
按照习惯直接看源码注释
Class used to run a message loop for a thread. 用于为线程运行消息循环的类。
好了,我们来看一下Looper如何运行消息循环
2.构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
这里初始化了MessageQueue对象,习惯性看一下该类的注释
/**
* Low-level class holding the list of messages to be dispatched by a
* {@link Looper}. Messages are not added directly to a MessageQueue,
* but rather through {@link Handler} objects associated with the Looper.
*
保存由{@link Looper}调度的消息列表。消息不是直接添加到MessageQueue,而是通过与Looper关联的{@link Handler}对象添加。
明白了就是用来保存消息的队列, 而消息是通过handler添加进来的
3.Looper 如何运行消息循环
接着翻源码,很快可以找到这个最长的方法体loop()方法
/**
* Run the message queue in this thread. Be sure to call 在此线程中运行消息队列。一定要调用
* {@link #quit()} to end the 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;
}
...
msg.target.dispatchMessage(msg);
...
}
}
方法比较长,这里只看关键部分,方法内部有一个死循环不停的从MessageQueue对象中获取消息体,并且调用了message内不的target对象的dispatchMessage方法来处理消息。
@UnsupportedAppUsage
/*package*/ Handler target;
看一下target对象,得知最终会交给handler处理消息。
4.形成闭环
现在我们想知道handler是何时赋值到Message的target对象上的,通过上面对MessageQueue类的注释,Message是通过Handler添加到MessageQueue中的,可以联想到handler常用的sendMessage(@NonNull Message msg)方法
/**
* Pushes a message onto the end of the message queue after all pending messages
* before the current time. It will be received in {@link #handleMessage},
* in the thread attached to this handler.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*/
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
继续看最终调用的方法
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在这里将当前对象赋值到target上,并且将message添加到MessageQueue 中。
通过分析looper这里同时得出handler的工作机制:
1.Handler初始化时需要获取当前线程的Looper对象,Looper对象创建时会同时创建MessageQueue对象。
2.Handler对象通过sendMessage方法生成Message对象(其中target为handler自身的引用),并且添加到Looper对象创建的MessageQueue中。
3.Looper对象会通过Loop方法运行消息循环,获取MessageQueue中的Message对象,然后调用target(handler)的dispatchMessage方法来处理消息。
扩展:深入理解MessageQueue
手打,如有错误或问题可留言:)