你只有努力奔跑,才能留在原地。
一. Handler
post or send message post 最终还是走send一样的逻辑代码:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), );
}
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, );
}
发送消息到messageQueue, messageQueue通过enqueueMessage method已单链表数据结构保存消息
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
处理Looper.loop 循环取出的消息
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) { // msg.callback 是post method 传入的回调
handleCallback(msg); // 该方法执行message.callback.run();
} else {
if (mCallback != null) { //public Handler(Callback callback, boolean async) 构造Handler的时候 mCallback = callback;
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
二. Looper
get message
通过loop() 方法进而MessageQueue.next()方法,循环取出MessageQueue里的Message。此处可能会死循环!
/**
* 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;
// 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
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
}
Message msg = queue.next(); 当msg == null,才退出循环;但是messageQueue.next(), 可能会一直死循环(block)!
MessageQueue.java
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == ) {
return null;
}
int pendingIdleHandlerCount = -; // - only during first iteration
int nextPollTimeoutMillis = ;
for (;;) {
...
}
}
get message 之后进而给 handler 处理相应的消息
msg.target.dispatchMessage(msg); //msg.target 就是对应的handler, handler send message 的时候这是handler send消息的时候保存在Messasg对象
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this; //这里传入的 handler类似接口回调
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}```
三. MessageQueue
由Looper构造方法创建,当调用Looper.prepare(); 系统将会创建一个对应的MessageQueue;
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper对象持有MessageQueue, Handler 通过拿到当前线程的Looper对象,进而拿到Looper的MessageQueue,再通过上面的post或者send Message到MessageQueue; Looper.loop(), 一直循环取出Message, 进而给对应的Handler处理(dispatchMessage method 处理)
四. ThreadLocal
ThreadLocal一般用来保存每个Thread特有的对象或者属性;
Looper对象就是保存在ThreadLocal里面的,通过ThreadLocal.set() save Looper对象,ThreadLocal.get() get Looper对象; 线程中只能有不超过一个Looper对象,并且Thread 跟Looper对象一对一的关系;这样用ThreadLocal来存取Looper, 就不用一个类型LooperManager类来管理所有Thread的Looper对象了。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
验证一下ThreadLocal.get(), ThreadLocal.set() 方法,以及ThreadLocal在多个Thread中是怎么保持自我的。
private static void testThreadLocal() {
final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
new Thread() {
@Override
public void run() {
super.run();
threadLocal.set();
System.out.println("Thread name: " + Thread.currentThread() + " threadLocal value: " + threadLocal.get());
}
}.start();
new Thread() {
@Override
public void run() {
super.run();
threadLocal.set();
System.out.println("Thread name: " + Thread.currentThread() + " threadLocal value: " + threadLocal.get());
}
}.start();
System.out.println("Thread name: " + Thread.currentThread() + " threadLocal value: " + threadLocal.get());
}
log:
Thread name: Thread[Thread-,,main] threadLocal value:
Thread name: Thread[Thread-,,main] threadLocal value:
Thread name: Thread[main,,main] threadLocal value: null