阅读者三篇Android绘制文章,会让你对理解Android绘制有帮助:
- Android Render(一)Activity窗口构成和绘制解析
- Android Render(二)7.1源码硬件加速下draw绘制流程分析
- Android Render(三)supportVersion 27.0.0源码RecyclerView绘制流程解析
一、Activity窗口构成
这里我们会介绍到Activity
、PhoneWindow
、DecorView
、ViewRootImpl
、WindowManagerImpl
、WindowManagerGlobal
、ActivityThread
和Surface
,关于Activity窗口有很多方面可讲,我这里只侧重于Activity窗口的Render方面来讲解。先来两张张大家早已经烂熟于心的图:
一个Activity的构成有,Activity
、PhoneWindow
、DecorView
,再加上DecorView里面的TitleBar和我们填充的content内容,这些还Activity构成需要的具体类,不是一些辅助类,其实还有ViewRootImpl
、WindowManagerImpl
、WindowManagerGlobal
、ActivityThread
这几个不可见的辅助类,虽然是Activity构成可见UI界面没用到,但是这几个辅助类都是直接或者间接负责了Activity的构建和绘制的。下面我按照我的理解来一一介绍这些类的作用和被创建时机,有不对的地方还请大家指正:
-
Activity:一个继承
ContextThemeWrapper
的类,继承自ContextThemeWrapper那么意味着,通过Activity可以访问当前包的资源(getResources、getAssets)和启动其他组件(Activity、Service、Broadcast)以及得到各种服务(getSystemService),并且定义了当前Activity的Theme
主题类型 ,关于Context的解释请看:http://www.cnblogs.com/android100/p/Android-Context.html
并且只有创建了一个Activity才会创建后面的PhoneWindow、DecorView、ViewRootImpl、WindowManagerImpl、和Surface这些类。我这里并没说ActivityThread类,ActivityThread是Android应用的主线程(UI线程),一个应用进程才有一个UI线程。也没有说WindowManagerGlobal类,这个类用了几个数组管理一个应用进程内所有Activity的DecorView和ViewRootImpl以及WindowManager对应关系的。WindowManagerGlobal
是一个单例的类,一个应用进程内也只有一个。但是WindowManagerImpl是每一个Activity都有一个的。Activity是在ActivityThread的performLaunchActivity方法中用ClassLoader类加载器创建出来的。 -
PhoneWindow: 一个继承于抽象类Window的类,也是Window的唯一实现类。在Activity中PhoneWindow处在顶级位置,但是PhoneWindow是一个不可见的类,PhoneWindow内的DecorView才是我们可见的UI布局,但是我们可见的UI布局为啥要包装一层PhoneWindow列?经过我的多次查看源代码和推敲,我发现
PhoneWindow
负责了Activity UI界面顶级布局DecorView的创建,PhoneWindow保存了window attributes即窗口布局属性参数,保存了与WindowManagerService进程通讯的IBinder (取名token)方便去系统WindowManagerService进程通讯,并且负责了用户Key和Touch事件的分发,但是PhoneWindow分发事件也是交给了DecorView来完成的。除了我们Activity在setContent时PhoneWindow创建了DecorView,好像PhoneWindow
并没有负责太多的Render的事件。看源码确实就是如此啊!,其实真正的Render操作都在ViewRootImpl
类中。PhoneWindow是在Activity的attach方法中new出来的。 -
WindowManagerImpl: 见名知意,就是管理Window的,在这里就是管理
PhoneWindow
的,每一个Activity
都有一个自己的WindowManagerImpl
来管理自己的PhoneWindow,WindowManagerImpl其实是用来管理PhoneWindow里面的DecorView的,也可能是DecorView级别的其他的View,还有就是WindowManagerImpl是用来跟一个App全局的PhoneWindow管理器WindowManagerGlobal通信的,添加、移除和更新DecorView层级的View时WindowManagerImpl会调用WindowManagerGlobal中的方法来进行全局管理。WindowManagerImpl是在Activity的attach方法中new PhoneWindow后调用mWindow.setWindowManager方法创建的,其内部是调用setWindowManager的createLocalWindowManager方法new出来的。 -
DecorView: 是一个ViewGroup,继承自FrameLayout,是我们看到的UI界面的顶级容器,DecorView是PhoneWindow的成员。
DecorView
除了是Activity界面的顶级容器以外,DecorView还是key和touch事件从上向下真正分发开始的源头。事件分发从Activity—》PhoneWindow—》DecorView—》层层向下分发到我们的界面底层。DecorView其实在很多地方都会创建,PhoneWindow内部的getDecorView方法被调用时,要是内部的成员变量mDecor为空的话,就会调用installDecor()方法去创建一个DecorView,最后new 一个DecorView返回,保证调用PhoneWindow的getDecorView获取 DecorView时永远不会为空。我看代码发现PhoneWindow的DecorView第一次调用发生在ActivityThread内的handleResumeActivity方法中,handleResumeActivity方法中还有一个很关键的步骤,就是调用了WindowManagerImpl的addView(DecorView,WindowManager.LayoutParams )方法,进去创建了一个跟DecorView关联的ViewRootImpl类。 -
ViewRootImpl:是一个实现了
ViewParent
接口的final类。我前面说到了,ViewRootImpl主要是负责Activity的界面Render绘制的,负责整个窗口界面的ViewTree的绘制更新。ViewRootImpl要负责DecorView的绘制,那么ViewRootImpl就需要持有当前Activity的DecorView的引用,是的,的确如此,前面介绍DecorView的创建的时候我说到了DecorView第一次创建发生在ActivityThread
内的handleResumeActivity方法中,handleResumeActivity方法中还有一个很关键的步骤,就是调用了WindowManagerImpl
的addView(DecorView,WindowManager.LayoutParams )方法,进去创建了一个跟DecorView关联的ViewRootImpl类。WindowManagerImpl的addView方法其实调用了WindowManagerGlobal的addView方法,在这个方法中创建了ViewRootImpl,并且在这个方法中调用了ViewRootImpl的setView方法,使ViewRootImpl持有DecorView的引用。并且把实现了ViewParent
接口的自己设置成了DecorView的Parent。这样ViewRootImpl就可以肆无忌惮地操作DecorView了。其实我在调用普通view的invalidate()刷新时,其实是经过层层Parent寻找,最终调用了最顶层的ParentViewRootImpl的invalidate()来判断和处理每次的UI界面刷新的。 -
Surface:一个实现了
Parcelable
接口的类,对Parcelable接口不了解的,请看我之前的Binder通信的文章:Android IPC之AIDL看这一篇还不够。Surface
是原始图像缓冲区(raw buffer)的一个句柄,而原始图像缓冲区是由屏幕图像合成器(screen compositor)管理的。得到了Surface
这个句柄就可以得到其中的Canvas、原生缓冲器以及其它方面的内容。所以说Surface
是生成Canvas的地方,具体就是调用lockCanvas方法获得Canvas。至于Canvas、Paint 和Bitmap的关系我这里就不讲了,后面会有文章来讲这个。Surface是ViewRootImpl的一个final成员变量,伴随ViewRootImpl的创建默认就new一个出来了,但是此时的Surface是一个空的,里面是没有内容的。Surface的数据填充是要跟WindowManagerService
交互的,应用进程端Binder通知WindowManagerService进程端创建一个Surface对象,最后是将WindowManagerService进程端的 Surface对象传递到应用进程端并赋值给应用进程的Surface对象,这样窗口可以使用Surface来绘制UI了。因为Surface对象要夸进程传递,所以Surface要实现Parcelable
接口。更详细的介绍关于窗口的Surface创建请看老罗的:Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析
二、Activity窗口创建流程
上面的名词介绍其实就是按照窗口的创建流程的顺序来讲的,但是单单是文字不够直观,下面以箭头加方法名的形式展现一下,源码分析流程基于Android7.1
/**1*/ ApplicationThread的onTransact方法接收到SystemServer进程的SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION启动Activity的Binder信息
↓
/**2*/ ApplicationThread.scheduleLaunchActivity() //
↓
/**3*/ ActivityThread.scheduleLaunchActivity() //安排启动Activity
↓
/**4*/ ActivityThread.handleLaunchActivity() //处理启动Activity
↓
/**5*/ ActivityThread.handleResumeActivity() // Activity 的Resume会使DecorView跟ViewRootImpl关联
↓
/**6*/ WindowManagerGlobal.addView() //全局保存窗口的信息
↓
/**7*/ ViewRootImpl.setView() //使DecorView和ViewRootImpl关联并绘制界面
↓
/**8*/ ViewRootImpl.requestLayout() //请求绘制ViewTree
↓
/**9*/ ViewRootImpl.scheduleTraversals() // 安排遍历
↓
/**10*/ ViewRootImpl.doTraversal() //
↓
/**11*/ ViewRootImpl.performTraversals() //执行遍历 会根据情况调用relayoutWindow performMeasure performLayout performDraw 等方法 这四个方法跟绘制是紧密相关的
↓
/**12*/ ViewRootImpl.relayoutWindow() //窗口第一次创建或者是窗口大小有变化并且窗口可见就会调用此方法
↓
/**13*/ ViewRootImpl.mWindowSession.relayout() //binder通信通知WindowManagerService创建一个跟应用端关联的Surface
↓
/**14*/ ViewRootImpl调用performMeasure performLayout performDraw方法绘制UI
其实第五步ActivityThread.handleResumeActivity()方法内会调用到WindowManagerGlobal.addView()方法把窗口绘制完成,紧接着就调用到了activity.makeVisible()方法,其实就是显示出DecorView,因为DecorView创建绘制前是被设置成了INVISIBLE的,Activity中的makeVisible方法就是把绘制完成的DecorView显示出来了:
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE); //把DecorView设置成可见的
}
至此我们就看到Activity界面上的UI了。
关于Activity的绘图表面(Surface)的创建过程我还想多说一下,以及Surface跟Activity的对应关系。
Surface是ViewRootImpl的一个final成员变量,伴随ViewRootImpl的创建默认就new一个出来了,但是此时的Surface是一个空的,里面是没有内容的。Surface的数据填充是要跟
WindowManagerService
交互的,应用进程端Binder通知WindowManagerService进程端创建一个Surface对象,最后是将WindowManagerService进程端的 Surface对象传递到应用进程端并赋值给应用进程的Surface对象,这样窗口可以使用Surface来绘制UI了。因为Surface对象要夸进程传递,所以Surface要实现Parcelable
接口。
从Activity窗口创建的流程我们可以知道:
-
每一个应用程序窗口都对应有两个Java层的Surface对象,其中一个是在
WindowManagerService
服务这一侧创建的,而另外一个是在应用程序进程这一侧创建的。 -
在WindowManagerService服务这一侧创建的Java层的Surface对象在C++层关联有一个
SurfaceControl
对象,用来设置应用窗口的属性,例如,大小和位置等。 -
在应用程序进程这一侧创建的ava层的
Surface
对象在C++层关联有一个Surface对象,用来绘制应用程序窗品的UI。
三、Activity窗口组件之间的对应关系
一个设备有一个WindowManagerService进程
有一个SystemServer进程
一个App
有一个WindowManagerGlobal类
有一个ActivityThread类
有一个ApplicationThread类
一个App
可以有很多个Activity
一个 Activity
有一个PhoneWindow类
一个PhoneWindow类
有一个ViewRootImpl类
一个PhoneWindow类
有一个WindowManagerImpl类
一个ViewRootImpl类
有一个Surface类
有一个DecorView类
用一张图表示:
Android设备构成图
参考文章:
Android应用程序窗口(Activity)的绘图表面(Surface)的创建过程分析
从源码看invalidate和requestLayout的区别
Android Render系列规划篇
Android应用层View绘制流程与源码分析
网友评论
1.PhoneWindow保存IBinder token与WindowManagerService通信?这个具体是如何体现的.
2.ViewRootImpl的setView()方法里面,把实现了ViewParent接口的自己设置成了DecorView的Parent这个在源码里面是如何体现的?