【记录一个问题】
主线程创建一个Handler,在子线程中去调用sendMessage,为什么消息能在主线程中得到处理?
- Handler的关联:在主线程中创建的
Handler自动与主线程的Looper关联。- 消息队列的共享:
sendMessage方法将消息发送到与Handler关联的Looper的MessageQueue中,这个MessageQueue是由Looper管理的,而Looper是在主线程中运行的。- Looper的循环:主线程中的
Looper不断地从MessageQueue中取出消息并处理它们,直到Looper被显式地停止。
目录
Handler流程
1. 异步通信准备
在开启应用或者说创建线程的时候就会去创建循环器对象Looper、消息队列MessageQueue;
(以HandlerThread为例)
HandlerThread
- @Override
- public void run() {
- mTid = Process.myTid();
- Looper.prepare();
- synchronized (this) {
- mLooper = Looper.myLooper();
- notifyAll();
- }
- Process.setThreadPriority(mPriority);
- onLooperPrepared();
- Looper.loop();
- mTid = -1;
- }
Looper
- /** 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));
- }
ThreadLocal
- /**
- * Returns the value in the current thread's copy of this
- * thread-local variable. If the variable has no value for the
- * current thread, it is first initialized to the value returned
- * by an invocation of the {@link #initialValue} method.
- *
- * @return the current thread's value of this thread-local
- */
- 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();
- }
- /**
- * Sets the current thread's copy of this thread-local variable
- * to the specified value. Most subclasses will have no need to
- * override this method, relying solely on the {@link #initialValue}
- * method to set the values of thread-locals.
- *
- * @param value the value to be stored in the current thread's copy of
- * this thread-local.
- */
- public void set(T value) {
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null) {
- map.set(this, value);
- } else {
- createMap(t, value);
- }
- }
【总结】
ThreadLocal是一个创建线程局部变量的类,它的实现机制决定了这个变量的作用域是线程,其他线程访问不了,在Looper中通过prepare函数的设计,确保了一个ThreadLocal 只会和一个Looper进行绑定。通过这两个方式确保了一个线程只有一个ThreadLocal变量,一个ThreadLocal变量只有一个Looper从而形成了一一对应的关系。
当在主线程创建Handler如果不设置Looper的话,就会默认绑定当前线程的Looper;
1.Handler中有成员变量MessageQueue,用于消息存放;
- public Handler(@Nullable Callback callback, boolean async) {
- ......
- 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;
- mCallback = callback;
- mAsynchronous = async;
- mIsShared = false;
- }
2.从HandlerThread的run方法可以看出,prepare随后会调用Looper.loop()方法循环去MessagerQueue中去取出消息处理。
- public static void loop() {
- final Looper me = myLooper();
- if (me == null) {
- throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
- }
- ......
- me.mInLoop = true;
- for (;;) {
- if (!loopOnce(me, ident, thresholdOverride)) {
- return;
- }
- }
- }
2.消息入队
当创建子线程/主线程创建Handler/子线程调用主线程的Handler去sendMessage,就会将该Message发送到与Handler关联的对应Looper初始化所创建的消息队列MessageQueue中。
不论是调用Handler的sendMessage还是sendEmptyMessage方法,最终都是调用sendEmptyMessageDelayed。
- public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
- Message msg = Message.obtain();
- msg.what = what;
- return sendMessageDelayed(msg, delayMillis);
- }
- public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
- if (delayMillis < 0) {
- delayMillis = 0;
- }
- return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
- }
Message obtain方法是从线程池中取出一个Message,sPool(是Message对象)后移一个,将其flag和next置空,线程池为空则创建一个新Message。
- /**
- * Return a new Message instance from the global pool. Allows us to
- * avoid allocating new objects in many cases.
- */
- 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();
- }
最终调用到sendMessageAtTime的目的是传入当前时间+延时时间,以时间为轴将当前Message插入到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);
- }
此处1个关键点
将当前Handler传给Message的target,这个在后面dispatchMessage时候会使用到;
- 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);
- }
MessageQueue
关键点msg.when就是传入的时间点,通过when,循环找到小when,插入当前Message。
- boolean enqueueMessage(Message msg, long when) {
- if (msg.target == null) {
- throw new IllegalArgumentException("Message must have a target.");
- }
- synchronized (this) {
- if (msg.isInUse()) {
- throw new IllegalStateException(msg + " This message is already in use.");
- }
- if (mQuitting) {
- IllegalStateException e = new IllegalStateException(
- msg.target + " sending message to a Handler on a dead thread");
- Log.w(TAG, e.getMessage(), e);
- msg.recycle();
- return false;
- }
- msg.markInUse();
- msg.when = when;
- Message p = mMessages;
- boolean needWake;
- if (p == null || when == 0 || when < p.when) {
- // New head, wake up the event queue if blocked.
- msg.next = p;
- mMessages = msg;
- needWake = mBlocked;
- } else {
- // Inserted within the middle of the queue. Usually we don't have to wake
- // up the event queue unless there is a barrier at the head of the queue
- // and the message is the earliest asynchronous message in the queue.
- needWake = mBlocked && p.target == null && msg.isAsynchronous();
- Message prev;
- for (;;) {
- prev = p;
- p = p.next;
- if (p == null || when < p.when) {
- break;
- }
- if (needWake && p.isAsynchronous()) {
- needWake = false;
- }
- }
- msg.next = p; // invariant: p == prev.next
- prev.next = msg;
- }
- // We can assume mPtr != 0 because mQuitting is false.
- if (needWake) {
- nativeWake(mPtr);
- }
- }
- return true;
- }
3.消息循环
- 前面说到Looper.loop()循环去遍历MeassageQueue,此时当有消息进入就会将该消息取出,然后匹配到创建该消息的Handler中去处理;
- 如果MeassageQueue中没有消息,那就阻塞该线程,释放cpu。
LoopOnce主要两个重要作用
- 当MessageQueue中没有消息时候,返回false,结束线程
- 调用target的dispatchMessage进行消息的分发,target就是所创建的Handler
- private static boolean loopOnce(final Looper me,
- final long ident, final int thresholdOverride) {
- Message msg = me.mQueue.next(); // might block。//code1
- if (msg == null) {
- // No message indicates that the message queue is quitting.
- return false;
- }
- ......
- try {
- msg.target.dispatchMessage(msg); //code2
- if (observer != null) {
- observer.messageDispatched(token, msg);
- }
- dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
- }
- ......
- msg.recycleUnchecked();
- return true;
- }
code1中当没有消息时,或者消息不满足处理条件,则 nativePollOnce 方法会阻塞线程,直到有满足条件的消息到来。
【MessageQueue.next】
- Message next() {
- .......
- for (;;) {
- ......
- nativePollOnce(ptr, nextPollTimeoutMillis);//code1
- }
- }
【LoopOnce】
上述code2 dispatchMesage需要判断分发Message对象中的callback,如下三种情况:
- public void dispatchMessage(@NonNull Message msg) {
- if (msg.callback != null) {
- handleCallback(msg);//code 1
- } else {
- if (mCallback != null) {
- if (mCallback.handleMessage(msg)) {//code2
- return;
- }
- }
- handleMessage(msg);//code3
- }
- }
1. code1中是post中的Runnable,执行handleCallback(message.callback.run(););
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- ......
- }
- });
2. code2中是创建Handler的时候是否传入callback;
- mHandler = new Handler(threadLooper, new Handler.Callback() {
- @Override
- public boolean handleMessage(@NonNull Message msg) {
- if (msg.what == MSG_HELLO) {
- Log.d(TAG, "handleMessage: thread id: " + Thread.currentThread().getId());
- }
- finish();
- return true;
- }
- });
3. code3中是执行Handler中的handleMessage,Handler中重写该方法即可。
- private static class MyHandler extends Handler {
- MyHandler(Looper looper) {
- super(looper);
- }
- @Override
- public void handleMessage(@NonNull Message msg) {
- super.handleMessage(msg);
- }
- }
4.消息处理
Handler接收到message,在handleMessage中处理UI等相关操作。
- /**
- * Subclasses must implement this to receive messages.
- */
- public void handleMessage(@NonNull Message msg) {
- }
1031

被折叠的 条评论
为什么被折叠?



