AndroidUI绘制流程(二)
上篇文章中,我们讲到了UI绘制的三大步,最后我们的方法定位到了performTraversals()方法,而performTraversals的上游又是谁呢?我们接着继续分析
调用performTraversals()方法的寻找很简单,只有一个调用者doTraversal(),而doTraversal()的调用者是一个Runnable即TraversalRunnable,它的实例调用是
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
而它的调用者是ViewRootImpl中的scheduleTraversals()方法,这个方法的在很多处都有调用,而这里基本上是我们逆向分析的终点了,这里我们从主分支开始,即Activity的调用,即ViewRootImpl.requestLayout(),这个方法是我们经常要用到的,而且里面有一个我们常见的Exception(Only the original thread that created a view hierarchy can touch its views.)一些黑科技通过绕过这个方法在子线程刷新UI。
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
requestLayout()调用者也非常多,这里我们先到ViewRootImpl中找到setView方法,最终我们可以找到的是WindowManagerGlobal中的addView方法,WindowManagerGlobal是什么呢?通过UML图来简单了解一下。
WindowManager是一个控制窗口的管理类,addView、removeView、updateView都需要它的参与,但是它并不是自己处理的,WindowManager是一个接口,它更多的是一个Binder中Client的角色(可以先简单的认为要与系统的线程间通信)它的实现类其实是WindowManagerImpl,但我们查看WindowManagerImpl中其实并没有多少方法,大部分是通过WindowManagerGlobal去处理了,这里是一个代理模式的实现,这样的好处就是底层可以根据需要(比如有些优化,新版本特性)去改变底层实现,但是上层的接口依然可以沿用。
WindowManagerGlobal的addView方法中实例化了ViewRootImpl,通过ViewRootImpl我们就可以调用三大步来绘制UI。
在分析了WindowManagerGlobal之后,我们需要找到它的上层调用WindowManager,我们需要找到创建WindowManager的地方,而与Activity相关,并且初始化Window的地方只有在Activity中的attach方法
final void attach(Context context, ActivityThread aThread){
//省略一些代码
mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
mWindowManager = mWindow.getWindowManager();
}
这里只是创建了WindowManager,而真正调用addView的地方是在handleResumeActivity()方法中,而调用handleResumeActivity的地方是一个名叫H的Handler,而这个Handler是Activity启动的必经之路,所以我们的调用之路只能到这里了,在这之上的逻辑更多的是Activity的启动流程。
总结
面对复杂的调用,没有什么是比时序图能更好理解的了。
Android_Activity绘制时序图.png
坦白来说,这篇博客写的并不好,这样逆向分析对上一篇可能好用,但是这篇确实有点太牵强,之后再改改吧。博客写的不多,以后尽量多练习一下,要把这几年积累的都记录下来,加油。