android requestLayout等重绘分析

来源:互联网 发布:瑜伽 书籍 知乎 编辑:程序博客网 时间:2024/05/21 17:49

基于4.4.2 kitkat source code

ViewRootImpl 中的scheduleTraversals()会先判断是否有  mTraversalRunnable 被post到   mChoreographer那里,如果没有,那么就post一个mTraversalRunnable(CALLBACK类型是Choreographer.CALLBACK_TRAVERSAL)到mChoreographer(和mhandler不一样的,可能不是同一个线程), 之前会试取获得mhandler的一个syncBarrier, 该

Barrier的作用是将之后所有仿如到handler的callback都阻塞住不让其执行,直到该barrier被释放为止, 而释放barrier则是在unscheduleTraversals()中做的,加barrier的用途应该是在保证重绘期间不会被别的事情干扰,在unscheduleTraversals()和doTraversal()调用的时候会被释放,

TraversalRunnable的run执行了 -> doTraversal() -> performTraversals() -> performDraw() -> draw() -> (如果当前正在执行
动画,那么就继续scheduleTraversals()以实现动态变化)

ViewRootImpl的requestLayout()在当前没有正在处理的layoutRequest时,就会scheduleTraversals(),中间会检查thread, 保证调用
此方法的thread和创建viewRootImpl的thread是同一个。

ViewRootImpl implements ViewParent (自己实现了自己的requestLayout方法来实现ViewParent接口)
ViewGroup extends View implements ViewParent, ViewManager (没有重写View的requestLayout方法,直接使用了)
View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource
而ViewRootImpl是最上面的ViewParent,通过调用view的assignParent(this)将child的mparent指向自己,
而上面的View.java中的requestLayout(),会调用mparent的requestLayout()直到一路向上调用了ViewRootImpl的requestLayout(),从而引发了scheduleTraversals(),进一步导致重绘。

forceLayout()干的事情比requestLayout少的多,后者触发了一系列的重新layout以及重绘等繁琐操作,保证了刷新的及时性,而force_layout只是将view自己的mPrivateFlags 加上 PFLAG_FORCE_LAYOUT和PFLAG_INVALIDATED标记,使得在下一次layout的时候,会
重新计算自己的layout参数,但是并不会触发一次重绘

choreographer翻译过来是编舞者,其本质是一个协调器,在有新的绘制的请求过来时,为其决定真正执行的时机(不一定要有需求就满足,
比如,可以制定固定每秒重绘多少次,那么如果某个空档有绘制需求,该需求就会被delay到下一次的定时重绘中)

View的invalidate() -> 其parentView的invalidateChild(this, null) -> ViewGroup的invalidateChild(),该函数的最后会有一个while
循环,一直向上调用parent的invalidateChildInParent,知道最后到达ViewRootImpl的invalidateChildInParent -> invalidate()- > scheduleTraversals(). 可见View的invalidate()是会触发重绘的,不过不一定整个view tree都重绘,可能只重绘属于自己的一部分。

ViewRootImpl的draw会调用  drawSoftware() -> mView.draw(canvas) 而该mView是在ViewRootImpl通过setView设置的child View;

ViewGroup -> dispatchDraw() -> drawChild -> child view的draw() -> child view的 dispatchDraw()
0 0
原创粉丝点击