专栏名称: 刘望舒
腾讯云最具价值专家
目录
相关文章推荐
复利大王  ·  民生银行某员工业绩工资 ·  3 小时前  
复利大王  ·  江浙沪美女留子回国下嫁怀孕后悔 ·  2 天前  
复利大王  ·  某航离谱瓜! ·  2 天前  
复利大王  ·  某一线女网红下海? ·  2 天前  
51好读  ›  专栏  ›  刘望舒

深入理解Android消息机制

刘望舒  · 掘金  · android  · 2018-04-20 07:10

正文

请到「今天看啥」查看全文


Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {    @Override    public boolean queueIdle() {        return false    }});

我们可以在 queueIdle 中,趁着没有消息要处理,统计一下页面的渲染时间(消息发送完了说明UI已经渲染完了),或者算一下屏幕是否长时间没操作等等。

拿到 Message 对象后,会将 Message 分发到对应的 target 去

msg.target.dispatchMessage(msg);

查看源码

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

当 msg 的 callback 不为 null 的时候,即通过 post(Runnable) 发送信息的会执行 handlerCallback(msg) 方法。如果 mCallback 不为 null并且 handleMessage 的结果为 false,则执行 handleMessage 方法。否则会停止分发。

private static void handleCallback(Message message) {    message.callback.run();}

查看 handlerCallback 方法源码, callback 会得到执行。到这里基本的Android消息机制就分析完了,简而言之就是,Handler 不断的将Message发送到一 根据时间进行排序的优先队列里面,而线程中的 Looper 则不停的从MQ里面取出消息,分发到相应的目标Handler执行。

为什么主线程不卡?

分析完基本的消息机制,既然 Looper 的 looper 方法是一个for(;;;)循环,那么新的问题提出来了。为什么Android会在主线程使用死循环?执行死循环的时候为什么主线程的阻塞没有导致CPU占用的暴增?

继续分析在源码中我们没有分析的部分:

  1. 消息队列构造的时候是否调用了jni部分

  2. nativeWake、nativePollOnce这些方法的作用是什么

先查看MQ的构造方法:

MessageQueue(boolean quitAllowed) {    mQuitAllowed = quitAllowed;    mPtr = nativeInit();}

会发现消息队列还是和native层有关系,继续查看android/platform/frameworks/base/core/jni/android_os_MessageQueue_nativeInit.cpp中nativeInit的实现:

static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();    if (!nativeMessageQueue) {        jniThrowRuntimeException(env, "Unable to allocate native queue");        return 0;    }    nativeMessageQueue->incStrong(env);    return reinterpret_cast<jlong>(nativeMessageQueue);}

这里会发现我们初始化了一个 NativeMessageQueue ,查看这个消息队列的构造函数

NativeMessageQueue::NativeMessageQueue() :        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {    mLooper = Looper::getForThread();    if (mLooper == NULL) {        mLooper = new Looper(false);        Looper::setForThread(mLooper);    }}

这里会发现在mq中初始化了 native 的 Looper 对象,查看android/platform/framework/native/libs/utils/Looper.cpp中 Looper 对象的构造函数

// 简化后的代码Looper::Looper(bool allowNonCallbacks) :        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),        mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {    int wakeFds[2];    int result = pipe(wakeFds);    mWakeReadPipeFd = wakeFds[0];    mWakeWritePipeFd = wakeFds[1];    result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);    result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);    mEpollFd = epoll_create(EPOLL_SIZE_HINT);    struct epoll_event eventItem;    memset(& eventItem, 0, sizeof(epoll_event));     eventItem.events = EPOLLIN;    eventItem.data.fd = mWakeReadPipeFd;    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);}

这里我们会发现,在 native 层创建了一个epoll,并且对 epoll 的 event 事件进行了监听。

什么是epoll

在继续分析源码之前,我们先分析一下,什么是epoll







请到「今天看啥」查看全文