概述

一个大型嵌入式系统的视窗显示机制,通常包括两部分,窗口管理子系统、底层显示子系统,应用程序则是基于此之上,调用相关接口进行显示,并接受窗口管理。
Android当中,特有的应用组件模型、系统服务模型的设计,让这两块系统看似(就是)错踪复杂,通过大量的梳理之后,依然可以清晰地看到这两个子系统的设计。
还记得FrameWork那张大的架构图吗? 这里给出了清晰的视窗显示系统架构,明晰了应用程序与底层显示子系统的垂直关系。
[Android] [Android的视窗系统及显示机制][上]_第1张图片
多简单,应用程序上层通过较为熟知的绘图库,进行标准图形绘制,最后所有绘制数据均交给Surface对象。
最后,众多的Surface对象,将数据交给系统显示服务SurfaceFlinger进行整个系统的图形图像混合,最后输出到linux的framebbuffer里!
(哦,这里少给出了WMS与应用之间的关系图,见后)

具体来说,Android当中分三部分,应用程序显示机制,窗口管理子系统,底层显示子系统。

  • 应用程序显示机制
    涉及ActivityThread, Activity, View, ViewRoot,WMS,Window/PhoneWindow, WindowManager/LocalWindowManager/WindowPolicy, Surface
  • 窗口管理子系统
    涉及WMS,Window/PhoneWindow, WindowManager/LocalWindowManager/WindowPolicy
  • 底层显示子系统
    涉及Surface, SurfaceClient,SurfaceFlinger, XXXBuffer, openGL, Skia,framebuffer

目录

一个Activity的显示过程概述
一、应用程序显示机制
1.1 Activity的创建过程简述
1.2 Activity的绘制过程简述
1.3 Activity, View与Window的关系
1.4 Activity与Window, WindowManager, PolicyManager
1.5 Window与ViewRoot, DecorView,视图树之间的关系呢?
1.6 ViewRoot是什么?
1.7 View的绘制过程,自定义View
1.7.1 View树的绘制过程
1.7.2 自定义View
1.8 Surface类
1.9 ViewRoot和WMS的关系梳理
1.10 Activity总结 - 应用程序调用视窗管理子系统与底层显示子系统,完成显示、交互操作
二、View的绘制过程,自定义View
三、窗口管理子系统及输入事件的派发
四、底层显示子系统 - Surface与SurfaceFlinger的交互,SurfaceFlinger内部流程
(此篇见 [Android] [Android的视窗系统显示机制][SurfaceFlinger显示系统][下] )

一个Activity的显示过程概述

创建Activity
[–>ActivityThread.java]
private final voidhandleLaunchActivity(ActivityRecord r, Intent customIntent)
[–>ActivityThread.java]
private final ActivityperformLaunchActivity(ActivityRecord r, Intent customIntent) {
//其实Activity的创建过程中,建立了许多关系,这里略
调用Activity的onCreate函数,开始SDK中大书特书Activity的生命周期。
在onCreate函数中,我们一般会做什么呢?在这个函数中,和UI相关的重要工作就是调用setContentView来设置UI的外观。
分析setContentView
[–>Activity.java]
public void setContentView(View view) {
//getWindow返回的是什么呢?一起来看看。
getWindow().setContentView(view);
}
而后具体执行过程中,通过前述建立一系列关系,渲染View,最后辗转调用到绘制接口
[–>ViewRoot.java]
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;//mSurface是ViewRoot的成员变量

Canvascanvas;
canvas = surface.lockCanvas(dirty);

mView.draw(canvas);//调用DecorView的draw函数,canvas就是画布的意思啦!

//unlock画布,屏幕上马上就会见到漂亮宝贝的长相了。
surface.unlockCanvasAndPost(canvas);
}
绘制接口最终就是通过Binder跨进程调用到SurfaceFlinger的绘制服务,将本应用的显示数据交给SurfaceFlinger绘制,其余便是SurfaceFlinger的混合绘制工作了,最后写入linux的framebuffer完事。

一、应用程序显示机制

(ViewRoot的创建, ActivityThread/Activity/ViewRoot/Window/WindowManager之间的关系)
ActivityThread持有多个Activity,但当前有效于前台的Activity只有一个,该Activity持有ViewRoot对象。
(以上,假定已熟知Activity与ViewRoot的关系,那么程序运行中绘制的流程如下,比如点击或滑动界面触发绘制请求,这里初始过程需要首次绘制,最终绘制接口都是requestLayout)
ViewRoot的setView函数中,会有一个requestLayout。 //这是绘制请求的开端,触发整个绘制过程,其它绘制请求,最终也走这个流程下去
根据前面的分析可知,它会向ViewRoot发送一个DO_TRAVERSAL消息,来看它的handleMessage函数,代码如下所示:
[–>ViewRoot.java]
public void handleMessage(Message msg) {
switch (msg.what) {

case DO_TRAVERSAL:

performTraversals();//调用performTraversals函数

break;

}
}
再去看performTraversals函数,这个函数比较复杂,先只看它的关键部分,代码如下所示:
[–>ViewRoot.java]
private void performTraversals() {
finalView host = mView;//还记得这mView吗?它就是DecorView喔
booleaninitialized = false;
booleancontentInsetsChanged = false;
booleanvisibleInsetsChanged;
try {
relayoutResult= //①关键函数relayoutWindow
relayoutWindow(params, viewVisibility,insetsPending);
}

draw(fullRedrawNeeded);// ②开始绘制

}

1. relayoutWindow的分析 - 向WMS发起发绘制请求,待拿到Surface后,进行绘制

performTraversals函数比较复杂,暂时只关注其中的两个函数relayoutWindow和draw即可。先看第一个relayoutWindow,代码如下所示:
[–>ViewRoot.java]
private intrelayoutWindow(WindowManager.LayoutParams params,
int viewVisibility, boolean insetsPending)throws RemoteException {
//原来是调用IWindowSession的relayOut,暂且记住这个调用
int relayoutResult = sWindowSession.relayout(
mWindow, params,
(int) (mView.mMeasuredWidth * appScale + 0.5f),
(int) (mView.mMeasuredHeight * appScale + 0.5f),
viewVisibility, insetsPending, mWinFrame,
mPendingContentInsets, mPendingVisibleInsets,
mPendingConfiguration, mSurface); //mSurface做为参数传进去了。
}

}

2. draw的分析

再来看draw函数。这个函数非常重要,它可是Acitivity漂亮脸蛋的塑造大师啊,代码如下所示:
(很简洁,就是根视图发起draw调用,开始遍历子视图树,进行各自的绘制,最后所有绘制动作完成后,数据就在canvas对象里了,最后把canvas对象丢给surface,再丢过去给surfaceflinger就好了)
[–>ViewRoot.java]
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;//mSurface是ViewRoot的成员变量

Canvascanvas;
try {
int left = dirty.left;
int top = dirty.top;
int right = dirty.right;
int bottom = dirty.bottom;
//从mSurface中lock一块Canvas
canvas = surface.lockCanvas(dirty);

mView.draw(canvas);//调用DecorView的draw函数,canvas就是画布的意思啦!

//unlock画布,屏幕上马上就会见到漂亮宝贝的长相了。
surface.unlockCanvasAndPost(canvas);
}

}

拓展
  • ViewRoot的创建, ActivityThread/Activity/ViewRoot/Window/WindowManager之间的关系
  • ViewRoot绘制中,向WMS获取mSurface对象的过程
  • ViewRoot绘制中,向View视图树遍历绘制视图的过程(自定义View,应用开发必备 )
  • WMS是如何管理窗口的

1.3 Activity, View与Window的关系

1.4 Activity与Window, WindowManager, PolicyManager

在Activity的setContentView()执行过程中,涉及到了View与Window
上面出现了两个和UI有关系的类:View和Window[①]。来看SDK文档是怎么描述这两个类的。这里先给出原文描述,然后进行对应翻译:

· Window:abstract base class for a top-levelwindow look and behavior policy. An instance of this class should be used asthe top-level view added to the window manager. It provides standard UIpolicies such as a background, title area, default key processing, etc.

中文的意思是:Window是一个抽象基类,用于控制顶层窗口的外观和行为。做为顶层窗口它有什么特殊的职能呢?即绘制背景和标题栏、默认的按键处理等。
这里面有一句比较关键的话:它将做为一个顶层的view加入到Window Manager中。

· View:This class represents the basicbuilding block for user interface components. A View occupies a rectangulararea on the screen and is responsible for drawing and event handling.
View的概念就比较简单了,它是一个基本的UI单元,占据屏幕的一块矩形区域,可用于绘制,并能处理事件。
以下就是Activity中持有View类对象,它与WMS/Window之间的关系了,这是视窗子系统的基本组件。

(1)Activity的Window
据上文讲解可知,Window是一个抽象类。它实际的对象到底属于什么类型?先回到Activity创建的地方去看看。下面正是创建Activity时的代码,可当时没有深入地分析。
activity = mInstrumentation.newActivity(
cl,component.getClassName(), r.intent);
代码中调用了Instrumentation的newActivity,再去那里看看。
[–>Instrumentation.java]
public Activity newActivity(Class<?>clazz, Context context,
IBinder token, Application application, Intent intent,
ActivityInfo info, CharSequencetitle, Activity parent,
String id,Object lastNonConfigurationInstance)
throws InstantiationException, IllegalAccessException{
Activity activity = (Activity)clazz.newInstance();
ActivityThread aThread = null;
//关键函数attach!!
activity.attach(context, aThread, this, token, application, intent,
info, title,parent, id, lastNonConfigurationInstance,
new Configuration());
return activity;
}
看到关键函数attach了吧?Window的真相马上就要揭晓了,让我们用咆哮体②来表达内心的激动之情吧!!!!
[–>Activity.java]
final void attach(Context context,ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
Object lastNonConfigurationInstance,
HashMap lastNonConfigurationChildInstances,
Configuration config) {

//利用PolicyManager来创建Window对象
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);

//创建WindowManager对象
mWindow.setWindowManager(null, mToken, mComponent.flattenToString());
if(mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
//保存这个WindowManager对象
mWindowManager = mWindow.getWindowManager();
mCurrentConfig = config;
}
此刻又有一点失望吧?这里冒出了个PolicyManager类,Window是由它的makeNewWindow函数所创建,因此还必须再去看看这个PolicyManager。

(2)水面下的冰山——PolicyManager
PolicyManager定义于PolicyManager.java文件,该文件在一个非常独立的目录下,现将其单独列出来:
· frameworks/policies/base/phone/com/android/internal/policy/impl
注意,上面路径中的灰色目录phone是针对智能手机这种小屏幕的;另外还有一个平级的目录叫mid,是针对Mid设备的。mid目录的代码比较少,可能目前还没有开发完毕。
下面来看这个PolicyManager,它比较简单。
[–>PolicyManager.java]
public final class PolicyManager {
private static final String POLICY_IMPL_CLASS_NAME =
“com.android.internal.policy.impl.Policy”;
private static final IPolicy sPolicy;
static{
//
try {
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
//创建Policy对象
sPolicy = (IPolicy)policyClass.newInstance();
}catch (ClassNotFoundException ex) {

}
private PolicyManager() {}
//通过Policy对象的makeNewWindow创建一个Window
publicstatic Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}

}

这里有一个单例的sPolicy对象,它是Policy类型,请看它的定义。

(3)真正的Window
Policy类型的定义代码如下所示:
[–>Policy.java]
public class Policy implements IPolicy {
private static final String TAG = “PhonePolicy”;
private static final String[] preload_classes = {
“com.android.internal.policy.impl.PhoneLayoutInflater”,
“com.android.internal.policy.impl.PhoneWindow”,
“com.android.internal.policy.impl.PhoneWindow 1 " , " c o m . a n d r o i d . i n t e r n a l . p o l i c y . i m p l . P h o n e W i n d o w 1", "com.android.internal.policy.impl.PhoneWindow 1","com.android.internal.policy.impl.PhoneWindowContextMenuCallback”,
“com.android.internal.policy.impl.PhoneWindow D e c o r V i e w " , " c o m . a n d r o i d . i n t e r n a l . p o l i c y . i m p l . P h o n e W i n d o w DecorView", "com.android.internal.policy.impl.PhoneWindow DecorView","com.android.internal.policy.impl.PhoneWindowPanelFeatureState”,
“com.android.internal.policy.impl.PhoneWindow P a n e l F e a t u r e S t a t e PanelFeatureState PanelFeatureStateSavedState”,
};
static{
//加载所有的类
for (String s : preload_classes) {
try {
Class.forName(s);
} catch (ClassNotFoundException ex) {

}
}
}

public PhoneWindow makeNewWindow(Contextcontext) {
//makeNewWindow返回的是PhoneWindow对象
return new PhoneWindow(context);
}

}
至此,终于知道了代码:
mWindow = PolicyManager.makeNewWindow(this);
返回的Window,原来是一个PhoneWindow对象。它的定义在PhoneWindow.java中。
mWindow的真实身份搞清楚了,还剩下个WindowManager。现在就来揭示其真面目。

(4)真正的WindowManager
先看WindowManager创建的代码,如下所示:
[–>Activity.java]
…//创建mWindow对象
//调用mWindow的setWindowManager函数
mWindow.setWindowManager(null, mToken,mComponent.flattenToString());

上面的函数设置了PhoneWindow的WindowManager,不过第一个参数是null,这是什么意思?在回答此问题之前,先来看PhoneWindow的定义,它是从Window类派生。
[–>PhoneWindow.java::PhoneWindow定义]
public class PhoneWindow extends Windowimplements MenuBuilder.Callback
前面调用的setWindowManager函数,其实是由PhoneWindow的父类Window类来实现的,来看其代码,如下所示:
[–>Window.java]
public void setWindowManager(WindowManagerwm,IBinder appToken, String appName) { //注意,传入的wm值为null
mAppToken = appToken;
mAppName = appName;
if(wm == null) {
//如果wm为空的话,则创建WindowManagerImpl对象
wm = WindowManagerImpl.getDefault();
}
//mWindowManager是一个LocalWindowManager
mWindowManager = new LocalWindowManager(wm);
}
LocalWindowManager是在Window中定义的内部类,请看它的构造函数,其定义如下所示:
[–>Window.java::LocalWindowManager定义]
private class LocalWindowManager implementsWindowManager {
LocalWindowManager(WindowManager wm) {
mWindowManager = wm;//还好,只是简单地保存了传入的wm参数
mDefaultDisplay = mContext.getResources().getDefaultDisplay(
mWindowManager.getDefaultDisplay());
}

如上面代码所示,LocalWindowManager将保存一个WindowManager类型的对象,这个对象的实际类型是WindowManagerImpl。而WindowManagerImpl又是什么呢?来看它的代码,如下所示:
[–>WindowManagerImpl.java]
public class WindowManagerImpl implementsWindowManager {

public static WindowManagerImpl getDefault()
{
return mWindowManager; //返回的就是WindowManagerImpl对象
}
private static WindowManagerImpl mWindowManager= new WindowManagerImpl();
}

看到这里,是否有点头晕眼花?很多朋友读我的一篇与此内容相关的博文后,普遍也有如此反应。对此,试配制了一剂治晕药方,如图8-3所示:
Activity与Window, WindowManager, PolicyManager
Activity是一个应用组件,中文活动,代表与用户交互的一个操作对象。
它与Window, WindowManager, PolicyManager的关系如图:
[Android] [Android的视窗系统及显示机制][上]_第2张图片

一看便明了,Activity是活动,与用户交互,要有界面,当然需要window视窗对象啦,具体实现类便是PhoneWindow
那每个Activity都有个Window对象,那不乱了,那便要有视窗管理者啦,那便是WindowManager, PolicyManager …
根据上图,可得出以下结论:

  • Activity的mWindow成员变量其真实类型是PhoneWindow,而mWindowManager成员变量的真实类型是LocalWindowManager。
  • LocalWindowManager和WindowManagerImpl都实现了WindowManager接口。这里采用的是Proxy模式,表明LocalWindowManager将把它的工作委托WindowManagerImpl来完成。

1.5 Window与ViewRoot, DecorView,视图树之间的关系呢?

[Android] [Android的视窗系统及显示机制][上]_第3张图片
可从上图中看出,在Activity的onCreate函数中,通过setContentView设置的View,其实只是DecorView的子View。
DecorView还处理了标题栏显示等一系列的工作。
注意,这里使用了设计模式中的Decorator(装饰)模式,它也是UI编程中常用的模式之一。

1.6 ViewRoot是什么?

ViewParent接口。SDK的文档中有关于ViewParent的介绍。但它和Android基本绘图单元中的View却不太一样,比如:ViewParent不处理绘画,因为它没有onDraw函数。
[–>ViewRoot.java::ViewRoot定义]
public final class ViewRoot extends Handlerimplements ViewParent,
View.AttachInfo.Callbacks //从Handler类派生
{
private final Surface mSurface = new Surface();//这里创建了一个Surface对象
final W mWindow; //这个是什么?
View mView;
}
上面这段代码传达出了一些重要信息:
· ViewRoot继承了Handler类,看来它能处理消息。ViewRoot果真重写了handleMessage函数。稍侯再来看它。
· ViewRoot有一个成员变量叫mSurface,它是Surface类型。
· ViewRoot还有一个W类型的mWindow和一个View类型的mView变量。
其中,W是ViewRoot定义的一个静态内部类:
static class W extends IWindow.Stub
这个类将参与Binder的通信,以后对此再做讲解,先来介绍Surface类。

1.7 View的绘制过程,自定义View

1.7.1 View树的绘制过程
ViewRoot的setView函数中,会有一个requestLayout。根据前面的分析可知,它会向ViewRoot发送一个DO_TRAVERSAL消息,来看它的handleMessage函数,代码如下所示:
[–>ViewRoot.java]
public void handleMessage(Message msg) {
switch (msg.what) {

case DO_TRAVERSAL:

performTraversals();//调用performTraversals函数

break;

}
}
再去看performTraversals函数,这个函数比较复杂,先只看它的关键部分,代码如下所示:

[–>ViewRoot.java]
private void performTraversals() {
finalView host = mView;//还记得这mView吗?它就是DecorView喔
booleaninitialized = false;
booleancontentInsetsChanged = false;
booleanvisibleInsetsChanged;
try {
relayoutResult= //①关键函数relayoutWindow
relayoutWindow(params, viewVisibility,insetsPending);
}

draw(fullRedrawNeeded);// ②开始绘制

}

View的绘制流程是从ViewRoot.performTraversals()开始的,并通过调用performMeasure、performLayout、performDraw完成顶级View的三大流程
[Android] [Android的视窗系统及显示机制][上]_第4张图片

谈下我们的Activity,Activity启动后,的DecorView会被ViewRootImpl类的performTraversals方法去操作;

首先就是performMeasure的过程,这个方法会调用到View类的measure方法,这里并没有具体的测量实现,而是调用到了onMeasure,需要子类去实现;要知道DecorView其实就是个FrameLayout,是一个ViewGroup,重写onMeasure方法,去循环遍历子View的measure过程;根据自己的MeasureSpec和子View的LayoutParams来决定子View的测量规格,根据获得的测量规格得到子view的宽高,然后一层一层向下遍历,子类也会重写onMeasure方法,测量自己的大小

这样所有的View测量结束,第二步就是performLayout了,默认是调用到了View类layout方法;如果是ViewGroup,就调用ViewGroup的layout方法,但是这个方法没有具体实现,还是调用到了View类的layout方法;View类的layout方法回调onLayout方法,要怎么确定位置由子类重写onlayout方法实现;这里DecorView去重写,自己实现,循环调用每个子View的layout方法,将上下左右坐标值传递给子View,确定子View的位置

接下来就是最后的绘制过程了,也就是第三步performDraw,继续走到ViewTreeObserver的dispatchOnDraw方法,通知所有注册了OnDrawListener接口的View去调用自己的onDraw()方法,绘制自己;DecorView因为是个ViewGroup,重写了dispatchDraw方法,循环调用每个子View的draw方法;最后就是每个子View重写onDraw方法绘制自身

关于performTraversals()方法,其代码量达到800行,其中还有很多细节处理,包括确定窗口大小,父子窗口、对话框处理,窗口的边衬,各种窗口属性、状态获取、判断等,与WMS交互等。
无论如何,那是另一个事情,关乎窗口管理,它产生的结果,用在上述视图树绘制的主体逻辑中。

上述performTraversals()方法执行过程中,在draw()之前,会先去向WMS申请有效的Surface对象,真正带显存的对象,以便后续draw的过程中,将canvas绘制结果交给Surface,最后丢过去给SurfaceFlinger
1. relayoutWindow的分析
performTraversals函数比较复杂,暂时只关注其中的两个函数relayoutWindow和draw即可。先看第一个relayoutWindow,代码如下所示:
[–>ViewRoot.java]
private intrelayoutWindow(WindowManager.LayoutParams params,
int viewVisibility, boolean insetsPending)throws RemoteException {
//原来是调用IWindowSession的relayOut,暂且记住这个调用
int relayoutResult = sWindowSession.relayout(
mWindow, params,
(int) (mView.mMeasuredWidth * appScale + 0.5f),
(int) (mView.mMeasuredHeight * appScale + 0.5f),
viewVisibility, insetsPending, mWinFrame,
mPendingContentInsets, mPendingVisibleInsets,
mPendingConfiguration, mSurface); mSurface做为参数传进去了。
}

}
relayoutWindow中会调用IWindowSession的relayout函数,暂且记住这个调用,在精简流程后再进行分析。
最后一个参数mSurface是客户窗口创建的,WmS内部将为该Surface对象分配真正的显存, 等该
函数返回后,应用程序就可以在该Surface中绘制了。

2. draw的分析
再来看draw函数。这个函数非常重要,它可是Acitivity漂亮脸蛋的塑造大师啊,代码如下所示:
(很简洁,就是根视图发起draw调用,开始遍历子视图树,进行各自的绘制,最后所有绘制动作完成后,数据就在canvas对象里了,最后把canvas对象丢给surface,再丢过去给surfaceflinger就好了)
[–>ViewRoot.java]
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;//mSurface是ViewRoot的成员变量

Canvascanvas;
try {
int left = dirty.left;
int top = dirty.top;
int right = dirty.right;
int bottom = dirty.bottom;
//从mSurface中lock一块Canvas
canvas = surface.lockCanvas(dirty);

mView.draw(canvas);//调用DecorView的draw函数,canvas就是画布的意思啦!

//unlock画布,屏幕上马上就会见到漂亮宝贝的长相了。
surface.unlockCanvasAndPost(canvas);
}

}

总结:
视图树的绘制过程,主体逻辑大致是:
触发视图重绘,最后执行ViewRoot.performTraversals(),来完成View树的重绘工作。
并通过调用performMeasure、performLayout、performDraw完成顶级View的三大流程,由DecorView开始,链式递归调用,遍历视图树进行三大流程的测量、布局、绘制工作。
最后,拿到canvas最对象,丢给mSurface,把绘制数据交给SurfaceFlinger去绘制。
其中,mSurface会通过requestWindow()方法,去向WMS申请有效的Surface对象。

1.7.2 自定义View

1.8 Surface类

好,一堆上层逻辑跑完,最终数据绘制完成,要丢给谁,surface,谁负责去跟底层显示系统交互,surface!
前文介绍的View、DecorView等都是UI单元,这些UI单元的绘画工作都在onDraw函数中完成。如果把onDraw想象成画图过程,那么画布是什么?
Android肯定不是“马良”,它也没有那支可以在任何物体上作画的“神笔”,所以我们需要一块实实在在的画布,这块画布就是Surface。SDK文档对Surface类的说明是:Handle on to a raw buffer thatis being managed by the screen compositor。这句话的意思是:
· 有一块Raw buffer,至于是内存还是显存,不必管它。
· Surface操作这块Raw buffer。
· Screen compositor(其实就是SurfaceFlinger)管理这块Raw buffer。
Surface和SF、ViewRoot有什么关系呢?相信,聪明的你此时已经明白些了,这里用图8-5描绘一下心中的想法:
[Android] [Android的视窗系统及显示机制][上]_第5张图片
结合之前所讲的知识,图8-5清晰地传达了如下几条信息:

  • ViewRoot有一个成员变量mSurface,它是Surface类型,它和一块Raw Buffer有关联。
  • ViewRoot是一个ViewParent,它的子View的绘画操作,是在画布Surface上展开的。
  • Surface和SurfaceFlinger有交互,这非常类似AudioTrack和AudioFlinger之间的交互。

1.9 ViewRoot和WMS的关系梳理

ViewRoot和WMS之间的关系,可用图8-6来表示:
[Android] [Android的视窗系统及显示机制][上]_第6张图片
总结一下图8-6中的知识点:
· ViewRoot通过IWindowSession和WMS进程进行跨进程通信。IWindowSession定义在IWindowSession.aidl文件中。这个文件在编译时由aidl工具处理,最后会生成类似于Native Binder中Bn端和Bp端的代码,后文会介绍它。
· ViewRoot内部有一个W类型的对象,它也是一个基于Binder通信的类,W是IWindow的Bn端,用于响应请求。IWindow定义在另一个aidl文件IWindow.aidl中。
为什么需要这两个特殊的类呢?简单介绍一下:
首先,来看IWindowSession.aidl对自己的描述:
· System private per-application interface to the window manager:也就是说每个App进程都会和WMS建立一个IWindowSession会话。这个会话被App进程用于和WMS通信。后面会介绍它的requestLayout函数。
再看对IWindow.adil的描述:
· API back to a client window that the Window Manager uses to informit of interesting things happening:这句话的大意是IWindow是WMS用来做事件通知的。每当发生一些事情时,WMS就会把这些事告诉某个IWindow。可以把IWindow想象成一个回调函数。
IWindow的描述表达了什么意思呢?不妨看看它的内容,代码如下所示:
[–>IWindow.aidl定义]
void dispatchKey(in KeyEvent event);
void dispatchPointer(in MotionEvent event, longeventTime,
boolean callWhenDone);
void dispatchTrackball(in MotionEvent event,long eventTime,
boolean callWhenDone);
明白了?这里的事件指的就是按键、触屏等事件。那么,一个按键事件是如何被分发的呢?下面是它大致的流程:
· WMS所在的SystemServer进程接收到按键事件。
· WMS找到UI位于屏幕顶端的进程所对应的IWindow对象,这是一个Bp端对象。
· 调用这个IWindow对象的dispatchKey。IWindow对象的Bn端位于ViewRoot中,ViewRoot再根据内部View的位置信息找到真正处理这个事件的View,最后调用dispatchKey函数完成按键的处理。
其实这些按键事件的分发机制可以拿Windows的UI编程来做类比,在Windows中应用程序的按键处理流程是:
· 每一个按键事件都会转化成一个消息,这个消息将由系统加入到对应进程的消息队列中。该进程的消息在派发处理时,会根据消息的句柄找到对应的Window(窗口),继而该消息就由这个Window处理了。
注意:上面的描述实际上大大简化了真实的处理流程,读者可在了解大体知识后进行更深入的研究。
上面介绍的是ViewRoot和WMS的交互,但是我们最关心的Surface还没有正式介绍,在此之前,还是先介绍Activity的流程。

1.10 Activity总结 - 应用程序调用视窗管理子系统与底层显示子系统,完成显示、交互操作

不得不承认的是前面几节的内容很多也很繁杂,为了让后面分析的过程更流畅轻松一些,所以我们必须要总结一下。关于Activity的创建和显示,前面几节的信息可提炼成如下几条:
· Activity的顶层View是DecorView,而我们在onCreate函数中通过setContentView设置的View只不过是这个DecorView中的一部分罢了。DecorView是一个FrameLayout类型的ViewGroup。
· Activity和UI有关,它包含一个Window(真实类型是PhoneWindow)和一个WindowManager(真实类型是LocalWindowManager)对象。这两个对象将控制整个Activity的显示。
· LocalWindowManager使用了WindowManagerImpl做为最终的处理对象(Proxy模式),这个WindowManagerImpl中有一个ViewRoot对象。
· ViewRoot实现了ViewParent接口,它有两个重要的成员变量,一个是mView,它指向Activity顶层UI单元的DecorView,另外有一个mSurface,这个Surface包含了一个Canvas(画布)。除此之外,ViewRoot还通过Binder系统和WindowManagerService进行了跨进程交互。
· ViewRoot能处理Handler的消息,Activity的显示就是由ViewRoot在它的performTraversals函数中完成的。
· 整个Activity的绘图流程就是从mSurface中lock一块Canvas,然后交给mView去自由发挥画画的才能,最后unlockCanvasAndPost释放这块Canvas。
这里和显示有关的就是最后三条了,其中最重要的内容都和Surface相关,既然mSurface是ViewRoot的本地变量,那就直接去看Surface。上面的代码分析一路走下来,真是比较流畅,波澜不惊,可事实果真如此吗?

更多相关文章

  1. 史上最全Android开发资料:资源、UI、函数库、测试、构建全套教程
  2. 【Android 内存优化】Bitmap 图像尺寸缩小 ( 考虑像素密度、针对
  3. Android intent 传递对象以及返回刷新
  4. android 上 webkit js 本地扩展之全局本地对象实现步骤
  5. android 测试读取LEB数据的函数
  6. Android 将一个数据对象保存到本地以及读取的方法
  7. android activity Intent 传值 传对象
  8. android生命周期函数大全——亲测
  9. 用Java 在 KSOAP中序列化复杂对象数组实体

随机推荐

  1. Android自学笔记(番外篇):全面搭建Linux环境
  2. Android之Bean属性通知类
  3. Android任务栏的图标显示
  4. Android 自定义Drawable 实现圆角矩形和
  5. 提示:Not targeting the latest versions
  6. android Drawable转Bitmap| Bitmap转byte
  7. 【原创】Android多个xml文件的使用
  8. Android: 判断网络连接状态及连接类型
  9. [置顶] Android GridView
  10. android webview显示HTML代码