Android View post 方法

本贴最后更新于 280 天前,其中的信息可能已经时异事殊

解析 View.post 方法。分析一下这个方法的流程。

说起 post 方法,我们很容易联想到 Handlerpost 方法,都是接收一个 Runnable 对象。那么这两个方法有啥不同呢?

Handler 的 post 方法

先来简单看一下 Handlerpost(Runnable) 方法。这个方法是将一个 Runnable 加到消息队列中,并且会在这个 handler 关联的线程里执行。

下面是关联的部分源码。可以看到传入的 Runnable 对象,装入 Message 后,被添加进了 queue 队列中。

Handler 有关的部分源码

// android.os Handler 有关的部分源码
public final boolean post(@NonNull Runnable r) {
    return sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

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

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 介绍

View 的 post 方法

我们直接跟着 post 的源码走。

public boolean post(Runnable action) {
    final AttachInfo attachInfo = mAttachInfo;
    if (attachInfo != null) {
        return attachInfo.mHandler.post(action);
    }

    // Postpone the runnable until we know on which thread it needs to run.
    // Assume that the runnable will be successfully placed after attach.
    getRunQueue().post(action);
    return true;
}

private HandlerActionQueue getRunQueue() {
    if (mRunQueue == null) {
        mRunQueue = new HandlerActionQueue();
    }
    return mRunQueue;
}

可以看到一开始就查询是否有 attachInfo,如果有,则用 attachInfo.mHandler 来执行这个任务。

如果没有 attachInfo,则添加到 View 自己的 mRunQueue 中。确定运行的线程后,再执行任务。

post(Runnable action) 的返回 boolean 值,如果为 true,表示任务被添加到消息队列中了。
如果是 false,通常表示消息队列关联的 looper 正在退出。

那么我们需要了解 AttachInfoHandlerActionQueue

AttachInfo

AttachInfoView 的静态内部类。View 关联到父 window 后,用这个类来存储一些信息。

AttachInfo 存储的一部分信息如下:

  • WindowId mWindowId window 的标志
  • View mRootView 最顶部的 view
  • Handler mHandler 这个 handler 可以用来处理任务

HandlerActionQueue

View 还没有 handler 的时候,拿 HandlerActionQueue 来缓存任务。HandlerAction 是它的静态内部类,存储 Runnable 与延时信息。

public class HandlerActionQueue {
    private HandlerAction[] mActions;
    
    public void post(Runnable action)
    public void executeActions(Handler handler)
    // ...

    private static class HandlerAction {
        final Runnable action;
        final long delay;
        // ...
    }
}

View 的 mRunQueue

将任务(runnable)排成队。当 View 关联上窗口并且有 handler 后,再执行这些任务。

/**
 * Queue of pending runnables. Used to postpone calls to post() until this
 * view is attached and has a handler.
 */
private HandlerActionQueue mRunQueue;

这个 mRunQueue 里存储的任务啥时候被执行?我们关注 dispatchAttachedToWindow 方法。

void dispatchAttachedToWindow(AttachInfo info, int visibility) {
    // ...
    // Transfer all pending runnables.
    if (mRunQueue != null) {
        mRunQueue.executeActions(info.mHandler);
        mRunQueue = null;
    }
    // ...
}

这个方法里调用了 mRunQueue.executeActions

executeActions(Handler handler) 方法实际上是用传入的 handler 处理队列中的任务。

而这个 dispatchAttachedToWindow 会被 ViewGroup 中被调用。

或者是 ViewRootImpl 中调用

host.dispatchAttachedToWindow(mAttachInfo, 0);

小结

View 的 post 方法,实际上是使用了 AttachInfohandler

如果 View 当前还没有 AttachInfo,则把任务添加到了 View 自己的 HandlerActionQueue 队列中,然后在 dispatchAttachedToWindow 中把任务交给传入的 AttachInfohandler。也可以这样认为,View.post 用的就是 handler.post

我们在获取 View 的宽高时,会利用 View 的 post 方法,就是等 View 真的关联到 window 再拿宽高信息。

流程图归纳如下
postflow1.png

  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    320 引用 • 309 回帖 • 348 关注
  • View
    11 引用 • 2 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
RustFisher
擅长使用工具的人 https://an.rustfisher.com 南宁