View.post 使用
-
确保执行 runnable 的时候,View 已经初始化完成。
-
可以在将 runnable 丢到 UI 线程去执行
Causes the Runnable to be added to the message queue. The runnable will be run on the user interface thread.
- 一个例子:
1 2 3 4 5 6
thread { //get image from network imageView.post { imageView.setImageDrawable(...) } }
-
使用场景:在 Activity -> onCreate()中我们获取不到view的长宽,但我们这样的话,我们就能得到啦:
1 2 3 4 5 6
override fun onCreate(savedInstanceState: Bundle?) { imageView.post { val imageWidth = imageView.width val imageHeight = imageView.height } }
源码浅析
-
post 方法是放在 View.java 中的,意味着所有 View 都能用。
-
post 源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/** * Causes the Runnable to be added to the message queue. * The runnable will be run on the user interface thread. */ public boolean post(Runnable action) { // mAttachInfo 是在 dispatchAttachedToWindow 方法中赋值的 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. // 保存到 View 的变量 mRunQueue 中,等待 dispatchAttachedToWindow 中调用 // executeActions方法, getRunQueue().post(action); return true; } void dispatchAttachedToWindow(AttachInfo info, int visibility) { mAttachInfo = info; ... if (mRunQueue != null) { mRunQueue.executeActions(info.mHandler); mRunQueue = null; } }
- 由上述可知,View.post 方法肯定是在 dispatchAttachedToWindow 时以及之后会被调用。
- 而且,都是通过 mAttachInfo.mHandler 来调用 runnable 的。
- 所以,一切都在 dispatchAttachedToWindow 的调用,经过查找,可以 确定是在 ViewRootImpl -> performTraversals() 中执行的,所以保证了在调用 runnable 之前已经调用过 measure,layout方法了
- 详细源码解析可以参考 View.post()到底干了啥, 以及View.post() 不靠谱的地方你知道吗?
和 runOnUiThread 有啥区别么?
1
2
3
4
5
6
7
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
源码很简单,可以知道 runOnUiThread 只是把 runable 丢到 UI线程,然后就马上执行了。没有像 View.post 一样只在 dispatchAttachedToWindow之后才会执行。
和MessageQueue.IdleHandler 有啥区别?
-
使用:
1 2 3 4 5 6 7
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { @Override public boolean queueIdle() { return false; } });
-
runnable 会在 MessageQueue 被清空的时候执行,使用场景可以有:
- 在 Activity 中等待所以UI显示完,再执行的操作。
- 作为一种懒执行的策略,不用在 CPU 高峰期占用资源。