从前面Android应用程序与Su易做图ceFlinger服务的关系概述和学习计划和Android系统Su易做图ce机制的Su易做图ceFlinger服务简要介绍和学习计划这两个系列的文章可以知道,每一个在C++层实现的应用程序窗口都需要有一个绘图表面,然后才可以将自己的UI表现出来。这个绘图表面是需要由应用程序进程请求Su易做图ceFlinger服务来创建的,在Su易做图ceFlinger服务内部使用一个Layer对象来描述,同时,Su易做图ceFlinger服务会返回一个实现了ISu易做图ce接口的Binder本地对象给应用程序进程,于是,应用程序进程就可以获得一个实现了ISu易做图ce接口的Binder代理对象。有了这个实现了ISu易做图ce接口的Binder代理对象之后,在C++层实现的应用程序窗口就可以请求Su易做图ceFlinger服务分配图形缓冲区以及渲染已经填充好UI数据的图形缓冲区了。
对于在Java层实现的Android应用程序窗口来说,它也需要请求Su易做图ceFlinger服务为它创建绘图表面,这个绘图表面使用一个Su易做图ce对象来描述。由于在Java层实现的Android应用程序窗口还要接受WindowManagerService服务管理,因此,它的绘图表面的创建流程就会比在C++层实现的应用程序窗口复杂一些。具体来说,就是在在Java层实现的Android应用程序窗口的绘图表面是通过两个Su易做图ce对象来描述,一个是在应用程序进程这一侧创建的,另一个是在WindowManagerService服务这一侧创建的,它们对应于Su易做图ceFlinger服务这一侧的同一个Layer对象,如图1所示:
图1 应用程序窗口的绘图表面的模型图
在应用程序进程这一侧,每一个应用程序窗口,即每一个Activity组件,都有一个关联的Su易做图ce对象,这个Su易做图ce对象是保在在一个关联的ViewRoot对象的成员变量mSu易做图ce中的,如图2所示:
图2 应用程序窗口在应用程序进程这一侧的Su易做图ce的实现
图2的类关系图的详细描述可以参考前面Android应用程序窗口(Activity)实现框架简要介绍和学习计划一文的图6,这里我们只关注Su易做图ce类的实现。在应用程序进程这一侧,每一个Java层的Su易做图ce对都对应有一个C++层的Su易做图ce对象,并且后者的地址值保存在前者的成员变量mNativeSu易做图ce中。C++层的Su易做图ce类的实现以及作用可以参考前面Android应用程序与Su易做图ceFlinger服务的关系概述和学习计划这个系列的文章。
在WindowManagerService服务这一侧,每一个应用程序窗口,即每一个Activity组件,都有一个对应的WindowState对象,这个WindowState对象的成员变量mSu易做图ce同样是指向了一个Su易做图ce对象,如图3所示:
图3 应用程序窗口在WindowManagerService服务这一侧的Su易做图ce的实现
图3的类关系图的详细描述可以参考前面Android应用程序窗口(Activity)实现框架简要介绍和学习计划一文的图7,这里我们同样只关注Su易做图ce类的实现。在WindowManagerService服务这一侧,每一个Java层的Su易做图ce对都对应有一个C++层的Su易做图ceControl对象,并且后者的地址值保存在前者的成员变量mSu易做图ceControl中。C++层的Su易做图ceControl类的实现以及作用同样可以参考前面Android应用程序与Su易做图ceFlinger服务的关系概述和学习计划这个系列的文章。
一个应用程序窗口分别位于应用程序进程和WindowManagerService服务中的两个Su易做图ce对象有什么区别呢?虽然它们都是用来操作位于Su易做图ceFlinger服务中的同一个Layer对象的,不过,它们的操作方式却不一样。具体来说,就是位于应用程序进程这一侧的Su易做图ce对象负责绘制应用程序窗口的UI,即往应用程序窗口的图形缓冲区填充UI数据,而位于WindowManagerService服务这一侧的Su易做图ce对象负责设置应用程序窗口的属性,例如位置、大小等属性。这两种不同的操作方式分别是通过C++层的Su易做图ce对象和Su易做图ceControl对象来完成的,因此,位于应用程序进程和WindowManagerService服务中的两个Su易做图ce对象的用法是有区别的。之所以会有这样的区别,是因为绘制应用程序窗口是独立的,由应用程序进程来完即可,而设置应用程序窗口的属性却需要全局考虑,即需要由WindowManagerService服务来统筹安排,例如,一个应用程序窗口的Z轴坐标大小要考虑它到的窗口类型以及它与系统中的其它窗口的关系。
说到这里,另外一个问题又来了,由于一个应用程序窗口对应有两个Su易做图ce对象,那么它们是如何创建出来的呢?简单地说,就是按照以下步骤来创建:
1. 应用程序进程请求WindowManagerService服务为一个应用程序窗口创建一个Su易做图ce对象;
2. WindowManagerService服务请求Su易做图ceFlinger服务创建一个Layer对象,并且获得一个ISu易做图ce接口;
3. WindowManagerService服务将获得的ISu易做图ce接口保存在其内部的一个Su易做图ce对象中,并且将该ISu易做图ce接口返回给应用程序进程;
4. 应用程序进程得到WindowManagerService服务返回的ISu易做图ce接口之后,再将其封装成其内部的另外一个Su易做图ce对象中。
那么应用程序窗口的绘图表面又是什么时候创建的呢?一般是在不存在的时候就创建,因为应用程序窗口在运行的过程中,它的绘图表面会根据需要来销毁以及重新创建的,例如,应用程序窗口在第一次显示的时候,就会请求WindowManagerService服务为其创建绘制表面。从前面Android应用程序窗口(Activity)的视图对象(View)的创建过程分析一文可以知道,当一个应用程序窗口被激活并且它的视图对象创建完成之后,应用程序进程就会调用与其所关联的一个ViewRoot对象的成员函数requestLayout来请求对其UI进行布局以及显示。由于这时候应用程序窗口的绘图表面尚未创建,因此,ViewRoot类的成员函数requestLayout就会请求WindowManagerService服务来创建绘图表面。接下来,我们就从ViewRoot类的成员函数requestLayout开始,分析应用程序窗口的绘图表面的创建过程,如图4所示:
图4 应用程序窗口的绘图表面的创建过程
这个过程可以分为10个步骤,接下来我们就详细分析每一个步骤。
Step 1. ViewRoot.requestLayout
[java]
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......
boolean mLayoutRequested;
......
public void requestLayout() {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
......
}
这个函数定义在文件frameworks/base/core/java/android/view/ViewRoot.java中。
ViewRoot类的成员函数requestLayout首先调用另外一个成员函数checkThread来检查当前线程是否就是创建当前正在处理的ViewRoot对象的线程。如果不是的话,那么ViewRoot类的成员函数checkThread就会抛出一个异常出来。ViewRoot类是从Handler类继承下来的,用来处理应用程序窗口的UI布局和渲染等消息。由于这些消息都是与Ui相关的,因此它们就需要在UI线程中处理,这样我们就可以推断出当前正在处理的ViewRoot对象是要应用程序进程的UI线程中创建的。进一步地,我们就可以推断出ViewRoot类的成员函数checkThread实际上就是用来检查当前线程是否是应用程序进程的UI线程,如果不是的话,它就会抛出一个异常出来。
通过了上述检查之后,ViewRoot类的成员函数requestLayout首先将其成员变量mLayoutRequested的值设置为true,表示应用程序进程的UI线程正在被请求执行一个UI布局操作,接着再调用另外一个成员函数scheduleTraversals来继续执行UI布局的操作。
Step 2. ViewRoot.scheduleTraversals
[java]
public final class ViewRoot extends Handler implements ViewParent,
View.AttachInfo.Callbacks {
......  
补充:移动开发 , Android ,