Android View post 方法

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

解析 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 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    335 引用 • 324 回帖
  • View
    11 引用 • 2 回帖

相关帖子

欢迎来到这里!

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

注册 关于
请输入回帖内容 ...