-
Notifications
You must be signed in to change notification settings - Fork 783
2019-08-21:View.post()为什么可以获取到宽高信息? #126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
不清楚哈哈哈哈 不过貌似 这样子做 会把任务推到最后 直到当前view绘制完成后 才能正常获取到宽高 当然 还有其他三种方法 可以正确获取到 |
因为view没绘制的时候post是添加到view内部的一个队列中,view创建好之后(啥viewattachwindows方法分发的时候会一起调用,而这个方法在view绘制完成之后执行,所以能拿到) |
其实我们调用的post方法执行流程有两种,一种是直接使用Handler去执行,第二是将我们的runabale存储到队列中。 |
这个问题讲清楚有点难度呀。 内部执行是通过handler 去执行的, View.post 如果在onCreate方法中调用,这时会把Runnable保存到一个缓存数组中,等到View的 dispatchAttachedToWindow 方法被调用时,去通过handler执行Runnable方法, dispatchAttachedToWindow就是View加载到Window时被调用的。https://www.cnblogs.com/dasusu/p/8047172.html |
这样写一般是在 Activity 的 onResume 方法中,因为 onResume 执行在 View 初始化之前,如果在 onResume 中直接获取 View 宽高是获取不到的。使用 view.post 就能获取到,因为 view.post 是向 主 Handler 的 MessageQueu 中插入一条带执行消息,但是因为系统在 ViewRoot 中初始化 View 时也是利用 Handler 机制,平且为了优先执行 View 的初始化设置了同步屏障,导致 view.post 插入的消息会在 View 初始化之后执行,那么肯定就能获取到 View 的宽高啦! |
View.post方法调用时,如果在 View 还没开始绘制时( Activity 的 onResume方法还没回调之前 或者onResume方法执行了,但是 ViewRootImpl 的 performTraversals 还没开始执行)就会用一个初始长度为 4 的数组缓存起来(Runnable 数量大于4时会进行扩容),ViewRootImpl 在初始化时创建了一个 View.AttchInfo 对象并绑定 ViewRootImpl 的 Handler ,该 Handler 也用于发送 View 绘制相关的 msg ; 等到 ViewRootImpl执行 performTraversals方法时(此时 Activity 已经回调了onResume),会配置 View 的 AttchInfo 对象并且通过 View 的 dispatchAttachedToWindow 方法传入到 View 里面完成绑定,在该方法中会取出 View 缓存的 Runnable 并用 View.AttchInfo 的 Handler 来进行 post 方法,这样子就会加入到 MessageQueue 里面进行排队,等到这些缓存 Runnable 执行时,主线程里面 View的绘制流程也就结束了,所以这时候 Looper 取出这些缓存的Runnable 执行时就可以拿到 View 的宽高 那么,什么情况下View.post 方法不会执行呢?如果 Activity 因为某些原因没有执行到 onResume 的话,无法顺利调用 ViewRootImpl 的 performTraversals 的话,View.post 方法就不会执行 |
一个view的大小的最终确定是在onlayout中,但是当我们打开Activity,执行onCreate方法的时候,view可能还没执行到onlayout方法,这也是为什么我们在onCreate的方法中,通过getWidth获取的宽度为0的原因,但是在View.post方法中,实现了一个Runnable,即添加了一个队列任务,在执行完setContentView方法之后,队列任务里面会多一条询问布局是否完成的任务,我们添加的这一个任务就是加在这个任务之后,所以通过view.post这个方法可以获取到view的宽和高 |
大概几点, 1.. Window 2.. viewGroup.addView 或者 activity.setContentView 引起 View 树变化; |
1、LAUNCH_ACTIVITY,SystemServer进程发起,在这个消息里边将view.post中提交的runnable对象缓存起来,当执行到dispatchAttachedToWindow方法时,将缓存中的runnable插入消息队列,然后执行performMeasure、performLayout、performDraw方法 |
最根本原因还是View#post这种方式提交的runnable的执行是在view树绘制完成之后才真正执行的。 |
这是来自QQ邮箱的假期自动回复邮件。
|
这是来自QQ邮箱的假期自动回复邮件。
您好,我最近正在休假中,无法亲自回复您的邮件。我将在假期结束后,尽快给您回复。
|
个人理解:
|
我们可能会在项目中经常这么做:
这么做是可以获取到
view
的宽高信息的,但是大家有想过为什么吗?The text was updated successfully, but these errors were encountered: