主线程的消息处理过程

105 阅读3分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

主线程的消息处理过程

首先我们先看一下handler的通常使用方法

public class MainActivity extends AppCompatActivity {
    Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message msg) {
            Log.d("message",(String)msg.obj);
            return false;
        }
    });
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = new Message();
                message.obj = "abc";
                handler.sendMessage(message);
            }
        }).start();

    }
}

这里handler所在的是主线程,所以比较特殊不需要创建Looper并且开启循环,我们发现只需要在其他线程发送消息给主线程,主线程就可以拿到消息进行处理

image.png 如图可知在主线程中拿到了message
接着我们结合之前说过的ThreadLocal,MesssageQueue,Looper,一起来说说主线程和一般线程通常情况下的消息传递机制。

先看主线程,我们在其他线程用sendMessage方法,这个方法经过一系列的检测加工最终会到sendMessageAtTime这个方法

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,为什么还要用sendMessage这种方法,直接调用handler里的CallBack的handleMessage方法进行处理不就好了?其实这样是不太好的,因为当有多个线程都需要主线程去处理消息的话,如果直接调用handleMessage必然会涉及到线程间的同步,如果某个Message的处理比较复杂,那么其他线程必然会一直被阻塞,所以采用消息队列作为缓冲是非常有必要的
我们接着说sendMessageAtTime方法,这个方法首先拿到当前线程的MessageQueue,前面介绍Looper的时候说过MessageQueue是存储在Looper中的,接着我们看看mQueue是怎么来的

public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
   mLooper = looper;
   mQueue = looper.mQueue;
   mCallback = callback;
   mAsynchronous = async;
}

查找源代码我们发现mQueue的确来自Looper,接着我们看看Looper又是怎么来的

public Handler(@Nullable Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }

    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;
}

查看源代码发现是Looper.myLooper(),这个方法之前我们在Looper这一节讲过,是从当前线程的ThreadLocal.ThreadLocalMap中取出的。 接着看sendMessageAtTime中的enqueueMessage方法

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);
}

这个方法对msg进行了进一步包装,然后往MessageQueue中插入了一条消息,至此handler的消息发送阶段结束。接着我们看消息的接收处理阶段
之前讲过,Looper会不断地从消息队列中取出消息,那么Looper取出消息后又是如何处理的呢? 查找源代码发现有这么一行代码

image.png msg.target.dispatchMessage(msg) 原来Looper最终是调用了Handler的dispatchMessage方法 接着看

public void dispatchMessage(@NonNull Message msg) {
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg);
    }
}

按照上面的写法,这里会走mCallback.handleMessage(msg),最终也就到了定义处理msg的地方了。