在Android系统中,一个Activity通常就表示一个页面,这个页面实际是由Window来管理的,每个Activity都对应着一个Window。Window是一个抽象类,具体实现类是PhoneWindow,对View进行管理。确切的来讲是,PhoneWindow包含一个DecorView类型的成员,代表这个Window的顶层View,是一个FrameLayout。DecorView的布局结构包含两部分:标题栏(title)和内容栏(content)。根据设置的主题不同,这两部分也会有不同的呈现。但内容栏是一定存在的,并且id是固定的android.R.id.content。
Window的创建过程
Window的创建过程是一个涉及多个层次和组件的复杂过程。
- 当启动一个Activity或系统通过Intent触发一个Activity时,这个Activity的生命周期开始。
- onCreate()方法被调用,这是Activity生命周期中的一个重要回调。
- 在onCreate()方法中,通常会调用setContentView()来设置Activity的布局。
- setContentView()方法会触发Window对象的创建。在Android中,每个Activity都与一个Window对象相关联。
- Window对象通常是一个PhoneWindow的实例,用于处理与窗口相关的各种功能。
Activity启动过程在ActivityThread的performLaunchActivity方法,会调用Activity的attach方法。与Activity相关联的Window对象就是在attach方法中创建的。
在attach方法中创建了一个PhoneWindow对象,并设置回调接口Callback和WindowManager。由于Activity类实现了Window.Callback接口,当Window接收到相关的事件触发时就会调用Activity的相应方法。Callback接口中的方法很多,有几个是我们比较常见的,比如dispatchTouchEvent、onAttachedToWindow、onDetachedFromWindow等。
Window的添加过程
- 与Window对象关联的是一个DecorView。DecorView是一个特殊的ViewGroup,包含了窗口的标题栏(如果有的话)和主要内容区域。
- DecorView的创建是在Window的创建过程中自动完成的,并且与Window对象紧密相关。
- 通过setContentView()方法加载的布局文件(通常是XML文件)会被解析并转换为相应的View对象。
- 这些View对象被添加到DecorView的内容区域中,形成一个View树。
- 绘制的结果被渲染到屏幕上,就能看到Activity的界面了。
ActivityThread的performLaunchActivity方法:
在Activity的attach方法返回后,程序会调用mInstrumentation.callActivityOnCreate方法,而这个方法最终会触发Activity的onCreate回调。而在onCreate中,会调用setContentView方法,开始Activity的Window添加过程。
Activity的setContentView方法内部调用的mWindow的setContentView方法,这个mWindow对象就是在attach方法中创建的PhoneWindow对象。
PhoneWindow的setContentView中,首先判断mContentParent是否存在,否则调用installDecor方法。这个mContentParent指的就是DecorView的内容栏。它的赋值就只有一个地方,就是在installDecor方法中。
如果mDecor为null,就先调用generateDecor方法创建DecorView。
DecorView对象创建之后,再判断mContentParent对象是否存在,不存在调用generateLayout方法。
generateLayout会返回一个ViewGroup对象contentParent,ID_ANDROID_CONTENT就是com.android.internal.R.id.content。
最后调用mLayoutInflater.inflate(layoutResID, mContentParent)方法,将Activity的布局视图添加到mContentParent中,回调Activity的onContentChanged方法通知Activity视图已经发生改变。
这个时候,Activity的视图布局还没有显示出来,DecorView还没有被WindowManager正式添加到窗口中。
在Activity执行onResume方法之后视图才能完全显示,并和用户正常交互,onResume方法是在ActivityThread的handleLaunchActivity方法中回调。
执行完performLaunchActivity方法返回一个Activity的实例,接下来判断如果创建的Activity实例不为null,就会执行handleResumeActivity方法。
在handleResumeActivity方法中,会调用performResumeActivity方法,经过层层调用最终会回调Activity的onResume方法。
handleResumeActivity中,在performResumeActivity方法执行之后,会调用Activity的makeVisible方法。
在makeVisible方法中,会调用WindowManager的addView方法,将DecorView正式添加到窗口中,同时DecorView设置为可见。
在WindowManagerImpl的addView方法内部,调用的是WindowManagerGlobal的addView方法。WindowManagerImpl通过桥接模式,将功能实现委托给了WindowManagerGlobal。WindowManagerGlobal是一个单例,说明一个进程中只有一个WindowManagerGlobal实例。每一个Window都会有一个相关联的WindowManagerImpl实例。
WindowManagerGlobal的addView方法主要完成三个步骤:
- 检查参数是否合法,如果是子Window还需要调整一些布局参数
- 创建ViewRootImpl,并将传进来的View添加到mViews列表里
- 通过ViewRootImpl来更新界面并完成Window的添加过程。
最终调用了root.setView(view, wparams, panelParentView)方法。
View树被构建完成,系统会遍历这个树,对每个View进行测量和布局,调用requestLayout方法会触发View层级的绘制遍历,requestLayout方法内部会调用scheduleTraversals方法。scheduleTraversals方法实际就是View绘制过程的入口。
然后会调用mWindowSession对象的addToDisplay方法,mWindowSession的类型是IWindowSession,是一个Binder对象,用于进程间通信,IWindowSession是Client端的代理。Server端实现是Session。代码都是运行在Activity所在的app进程,Session的addToDisplay方法则是运行在WMS所在的SystemServer进程中。
图片
addToDisplay方法内部调用了mService的addWindow方法,并将Session对象本身作为第一个参数传进去。mService就是WMS的实例,每一个app进程都会对应一个Session对象用来表示app进程与WMS的通信渠道。WMS会用ArrayList来存放这些Session对象。WMS会为这个要添加的窗口分配Surface,并确定窗口的显示次序,真正负责显示界面视图的是画布Surface而不是窗口本身。WMS会将所管理的Surface交由SurfaceFlinger处理,SurfaceFlinger会将这些Surface混合并绘制并最终呈现到屏幕上。