Android应用程序窗口(Activity)的窗口对象(Window) 的创建过程分析
每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一个具体的应用程序窗口。
每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一个具体的应用程序窗口。由此又可知,Activity只不过是一个高度抽象的UI组件,它的具体UI实现其实是由其它的一系列对象来实现的。在本文中,我们就将详细分析Android应用程序窗口对象的创建过程。
为了方便接下来描述类型为PhoneWindow的应用程序窗口的创建过程,我们将这两个图拿过来,如以下的图1和图2所示:

图1 Activity和Window的类关系图

图2 Window和PhoneWindow的类关系图
本文主要从Android应用程序窗口的创建过程来理解Activity、Window和PhonwWindow三个类的关系。
与Activity组件所关联的一个PhoneWindow对象是从Activity类的成员函数attach中创建的,如图3所示:

图3 Android应用程序窗口的创建过程
这个过程可以分为9个步骤,接下来我们就详细分析每一个步骤。
Step 1. Activity.attach
public class Activity extends ContextThemeWrapper  | 
这个函数定义在文件frameworks/base/core/java/android/app/Activity.java中。
函数首先调用PolicyManager类的静态成员函数makeNewWindow来创建一个类型为PhoneWindow的应用程序窗口,并且保存 在Activity类的成员变量mWindow中。有了这个类型为PhoneWindow的应用程序窗口,函数接下来还会调用它的成员函数 setCallback、setSoftInputMode和setWindowManager来设置窗口回调接口、软键盘输入区域的显示模式和本地窗口 管理器。
PhoneWindow类的成员函数setCallback、setSoftInputMode和setWindowManager都是从父类 Window继承下来的,因此,接下来我们就继续分析PolicyManager类的静态成员函数makeNewWindow,以及Window类的成员 函数setCallback、setSoftInputMode和setWindowManager的实现。
Step 2. PolicyManager.makeNewWindow
public final class PolicyManager {
 | 
这个函数定义在文件frameworks/base/core/java/com/android/internal/policy/PolicyManager.java中。
PolicyManager是一个窗口管理策略类,它在第一次被使用的时候,就会创建一个Policy类实例,并且保存在静态成员变量sPolicy中, 以后PolicyManager类的窗口管理策略就是通过这个Policy类实例来实现的,例如,PolicyManager类的静态成员函数 makeNewWindow就是通过调用这个Policy类实例的成员函数makeNewWindow来创建一个具体的应用程序窗口的。
接下来,我们就继续分析Policy类的成员函数makeNewWindow的实现。
Step 3. Policy.makeNewWindow
public class Policy implements IPolicy {
 | 
这个函数定义在文件frameworks/base/policy/src/com/android/internal/policy/impl/Policy.java中。
Policy类的成员函数makeNewWindow的实现很简单,它只是创建了一个PhoneWindow对象,然后返回给调用者。
接下来,我们就继续分析PhoneWindow类的构造函数的实现,以便可以了解一个类型为PhoneWindow的应用程序窗口的创建过程
Step 4. new PhoneWindow
public class PhoneWindow extends Window implements MenuBuilder.Callback {
 | 
这个函数定义在文件frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java中。
PhoneWindow类的构造函数很简单,它首先调用父类Window的构造函数来执行一些初始化操作,接着再调用LayoutInflater的静态成员函数from创建一个LayoutInflater实例,并且保存在成员变量mLayoutInflater中。这样,PhoneWindow类以后就可以通过成员变量mLayoutInflater来创建应用程序窗口的视图,这个视图使用类型为DecorView的成员变量mDecor来描述。PhoneWindow类还有另外一个类型为ViewGroup的成员变量mContentParent,用来描述一个视图容器,这个容器存放的就是成员变量mDecor所描述的视图的内容,不过这个容器也有可能指向的是mDecor本身。在后面的文章中,我们再详细分析类型为PhoneWindow的应用程序窗口的视图的创建过程。
Window的构造函数定义在文件frameworks/base/core/java/android/view/Window.java中,它的实现很简单,只是初始化了其成员变量mContext,如下所示:
public abstract class Window {
 | 
从前面的调用过程可以知道,参数context描述的是正在启动的Activity组件,将它保存在Window类的成员变量mContext之后,Window类就可以通过它来访问与Activity组件相关的资源了。
这一步执行完成之后,回到前面的Step 1中,即Activity类的成员函数attach中,接下来就会继续调用前面所创建的PhoneWindow对象从父类Window继承下来的成员函数setCallback来设置窗口回调接口,因此,接下来我们就继续分析Window类的成员函数setCallback的实现。
Step 5. Window.setCallback
public abstract class Window {
 | 
这个函数定义在文件frameworks/base/core/java/android/view/Window.java中。
正在启动的Activity组件会将它所实现的一个Callback接口设置到与它所关联的一个PhoneWindow对象的父类Window的成员变 量mCallback中去,这样当这个PhoneWindow对象接收到系统给它分发的IO输入事件,例如,键盘和触摸屏事件,转发给与它所关联的 Activity组件处理。
这一步执行完成之后,回到前面的Step 1中,即Activity类的成员函数attach中,接下来就会继续调用前面所创建的PhoneWindow对象从父类Window继承下来的成员函数 setSoftInputMode来设置应用程序窗口的软键盘输入区域的显示模式,因此,接下来我们就继续分析Window类的成员函数 setSoftInputMode的实现。
Step 6. Window.setSoftInputMode
public abstract class Window {
 | 
这个函数定义在文件frameworks/base/core/java/android/view/Window.java中。
参数mode有SOFT_INPUT_STATE_UNSPECIFIED、SOFT_INPUT_STATE_UNCHANGED、SOFT_INPUT_STATE_HIDDEN、SOFT_INPUT_STATE_ALWAYS_HIDDEN、SOFT_INPUT_STATE_VISIBLE和SOFT_INPUT_STATE_ALWAYS_VISIBLE一共六个取值,用来描述窗口的软键盘输入区域的显示模式,它们的含义如下所示:
- SOFT_INPUT_STATE_UNSPECIFIED:没有指定软键盘输入区域的显示状态。
 - SOFT_INPUT_STATE_UNCHANGED:不要改变软键盘输入区域的显示状态。
 - SOFT_INPUT_STATE_HIDDEN:在合适的时候隐藏软键盘输入区域,例如,当用户导航到当前窗口时。
 - SOFT_INPUT_STATE_ALWAYS_HIDDEN:当窗口获得焦点时,总是隐藏软键盘输入区域。
 - SOFT_INPUT_STATE_VISIBLE:在合适的时候显示软键盘输入区域,例如,当用户导航到当前窗口时。
 - SOFT_INPUT_STATE_ALWAYS_VISIBLE:当窗口获得焦点时,总是显示软键盘输入区域。
 
当参数mode的值不等于SOFT_INPUT_STATE_UNSPECIFIED时,就表示当前窗口被指定软键盘输入区域的显示模式,这时候Window类的成员函数setSoftInputMode就会将成员变量mHasSoftInputMode的值设置为true,并且将这个显示模式保存在用来描述窗口布局属性的一个WindowManager.LayoutParams对象的成员变量softInputMode中,否则的话,就会将成员变量mHasSoftInputMode的值设置为false。
设置完成窗口的软键盘输入区域的显示模式之后,如果Window类的成员变量mCallback指向了一个窗口回调接口,那么Window类的成员函数setSoftInputMode还会调用它的成员函数onWindowAttributesChanged来通知与窗口所关联的Activity组件,它的窗口布局属性发生了变化。
这一步执行完成之后,回到前面的Step 1中,即Activity类的成员函数attach中,接下来就会继续调用前面所创建的PhoneWindow对象从父类Window继承下来的成员函数setWindowManager来设置应用程序窗口的本地窗口管理器,因此,接下来我们就继续分析Window类的成员函数setWindowManager的实现。
Step 7. Window.setWindowManager
public abstract class Window {
 | 
这个函数定义在文件frameworks/base/core/java/android/view/Window.java中。
参数appToken用来描述当前正在处理的窗口是与哪一个Activity组件关联的,它是一个Binder代理对象,引用了在 ActivityManagerService这一侧所创建的一个类型为ActivityRecord的Binder本地对象。每一个启动起来了的Activity组件在ActivityManagerService这一侧,都有一个对应的 ActivityRecord对象,用来描述该Activity组件的运行状态。这个Binder代理对象会被保存在Window类的成员变量 mAppToken中,这样当前正在处理的窗口就可以知道与它所关联的Activity组件是什么。
参数appName用来描述当前正在处理的窗口所关联的Activity组件的名称,这个名称会被保存在Window类的成员变量mAppName中。
参数wm用来描述一个窗口管理器。从前面的调用过程可以知道, 这里传进来的参数wm的值等于null,因此,函数首先会调用WindowManagerImpl类的静态成员函数getDefault来获得一个默认的 窗口管理器。有了这个窗口管理器之后,函数接着再使用它来创建一个本地窗口管理器,即一个LocalWindowManager对象,用来维护当前正在处 理的应用程序窗口。
接下来,我们首先分析WindowManagerImpl类的静态成员函数getDefault的实现,接着再分析本地窗口管理器的创建过程,即LocalWindowManager类的构造函数的实现。
Step 8. WindowManagerImpl.getDefault
public class WindowManagerImpl implements WindowManager {
 | 
这个函数定义在文件frameworks/base/core/java/android/view/WindowManagerImpl.java中。
WindowManagerImpl类的静态成员函数getDefault的实现很简单,它只是将静态成员变量mWindowManager所指向的一个WindowManagerImpl对象返回给调用者,这个WindowManagerImpl对象实现了WindowManager接口,因此,它就可以用来管理应用程序窗口。
这一步执行完成之后,回到前面的Step 7中,即Window类的成员函数setWindowManager中,接下来就会使用前面所获得一个WindowManagerImpl对象来创建一个本地窗口管理器,即一个LocalWindowManager对象。
Step 9. new LocalWindowManager
public abstract class Window {
 | 
这个函数定义在文件frameworks/base/core/java/android/view/Window.java中。
LocalWindowManager类的构造函数首先将参数wm所描述的一个WindowManagerImpl对象保存它的成员变量mWindowManager中,这样以后就将窗口管理工作交给它来处理。
LocalWindowManager类的构造函数接着又通过成员变量mWindowManager所描述的一个WindowManagerImpl对象的成员函数getDefaultDisplay来获得一个Display对象,用来描述系统屏幕属性。
由于前面所获得的Display对象描述的是全局的屏幕属性,而当前正在处理的窗口可能配置了一些可自定义的屏幕属性,因此,LocalWindowManager类的构造函数需要进一步地调整前面所获得的Display对象所描述的屏幕属性,以便可以适合当前正在处理的窗口使用。LocalWindowManager类的构造函数首先通过外部类Window的成员变量mContext的成员函数getResources来获得一个Resources对象,接着再调用这个Resources对象的成员函数getDefaultDisplay来调整前面所获得的Display对象所描述的屏幕属性。最终调整完成的Display对象就保存在LocalWindowManager类的成员变量mDefaultDisplay中。
从前面的Step 4可以知道,类Window的成员变量mContext描述的是与当前窗口所关联的一个Activity组件。Activity类的成员函数getResources是从父类ContextWrapper继续下来的,它实现在文件frameworks/base/core/java/android/content/ContextWrapper.java中,如下所示:
public class ContextWrapper extends Context {
 | 
ContextWrapper类的成员变量mBase指向的是一个ContextImpl对象,用来描述一个Activity组件的运行上下 文环境。通过调用这个ContextImpl对象的成员函数getResources,就可以获得与一个Resources对象,而通过这个 Resources对象,就可以访问一个Activity组件的资源信息,从而可以获得它所配置的屏幕属性。
至此,我们就分析完成一个Activity组件所关联的应用程序窗口对象的创建过程了。从分析的过程可以知道:
- 一个Activity组件所关联的应用程序窗口对象的类型为PhoneWindow。
 - 这个类型为PhoneWindow的应用程序窗口是通过一个类型为LocalWindowManager的本地窗口管理器来维护的。
 - 这个类型为LocalWindowManager的本地窗口管理器又是通过一个类型为WindowManagerImpl的窗口管理器来维护应用程序窗口的。
 - 这个类型为PhoneWindow的应用程序窗口内部有一个类型为DecorView的视图对象,这个视图对象才是真正用来描述一个Activity组件的UI的。
 
http://www.uml.org.cn/mobiledev/201212272.asp
Android应用程序窗口(Activity)的窗口对象(Window) 的创建过程分析的更多相关文章
- Android应用程序资源管理器(Asset Manager)的创建过程分析
		
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8791064 在前面一篇文章中,我们分析了And ...
 - Android应用程序的Activity启动过程简要介绍和学习计划
		
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6685853 在Android系统中,Activ ...
 - Android应用程序中Activity的生命周期
		
Android应用程序中Activity的生命周期 对于Android来说Activity的生命周期是非常的重要,尤其是对于新学者来说,只有充分了解了Activity的生命周期,才能写出优良用户体验的 ...
 - 解开Android应用程序组件Activity的"singleTask"之谜
		
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6714543 在Android应用程序中,可以配 ...
 - Android应用程序注冊广播接收器(registerReceiver)的过程分析
		
前面我们介绍了Android系统的广播机制,从本质来说,它是一种消息订阅/公布机制,因此,使用这样的消息驱动模型的第一步便是订阅消息:而对Android应用程序来说,订阅消息事实上就是注冊广播接收器, ...
 - Android应用程序资源的查找过程分析
		
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8806798 我们知道,在Android系统中, ...
 - Android应用程序插件化研究之AssertManager
		
最近在研究Android应用的插件化开发,看了好几个相关的开源项目.插件化都是在解决以下几个问题: 如何把插件apk中的代码和资源加载到当前虚拟机. 如何把插件apk中的四大组件注册到进程中. 如何防 ...
 - Android应用程序窗口(Activity)的窗口对象(Window)的创建过程分析(转)
		
在前文中,我们分析了Android应用程序窗口的运行上下文环境的创建过程.由此可知,每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一 ...
 - 【转】Android应用程序窗口(Activity)窗口对象(Window)创建指南
		
在前文中,我们分析了Android应用程序窗口的运行上下文环境的创建过程.由此可知,每一个Activity组件都有一个关联的ContextImpl对象,同时,它还关联有一个Window对象,用来描述一 ...
 - Android应用程序窗口(Activity)实现框架简要介绍和学习计划
		
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8170307 前面我们学习了SurfaceFli ...
 
随机推荐
- java IO和NIO的场景选择
			
就使用上来说,传统的面向流的IO更简单,而面向缓冲(块)的NIO更复杂,因为可调整空间大,接口的概念性也更加低层(原生)些. 下面说说使用场景: IO的场景: 1.文件可能很多,但是size并不是那么 ...
 - Java并发3-多线程面试题
			
1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器编程,你可以使用多线程对运算密集型任务提速. 2) 线程和进程有什 ...
 - 2015第25周三iframe小结
			
一个 HTML页面可以有一个或多个子框架,这些子框架以<iframe>来标记,用来显示一个独立的HTML页面.这里所讲的框架编程包括框架的自我控制以及框架之间的互相访问,例如从一个框架中引 ...
 - HTML, CSS学习笔记(完整版)
			
第一章 div布局 前几课内容 .htm是早期的后缀.由于那时仅仅能支持长度为3的后缀.因此html与htm是一样的. shtml是server先处理然后再交给浏览器处理 #HTML小知识#之#XHT ...
 - [RxJS] Observables can throw errors
			
Whenever we are writing code, we need to remember that things may go wrong. If an error happens in a ...
 - Java基础知识强化47:StringBuffer类之StringBuffer的三个面试题
			
1. 面试题:String,StringBuffer,StringBuilder的区别 ? 答:String是字符串内容不可变的,而StringBuffer和StringBuilder是字符串内容长度 ...
 - ls 命令详解
			
1.ls基本语法及选项 用法:ls [选项]... [文件]... List information about the FILEs (the current directory by default ...
 - NS2仿真:两个移动节点网络连接及协议性能分析
			
NS2仿真实验报告2 实验名称:两个移动节点网络连接及协议性能分析 实验日期:2015年3月9日~2015年3月14日 实验报告日期:2015年3月15日 一.实验环境(网络平台,操作系统,网络拓扑图 ...
 - 关于Web安全的链接文章
			
1.CSRF(跨站请求伪造) http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html 2.深入理解JavaScript Hijacki ...
 - 模板模式(Template)
			
行为型:Template(模板模式) 作为一个曾经爱好写文章,但是不太懂得写文章的人,我必须承认,开头是个比较难的起步. 模板模式常规定义:模板模式定义了一个算法步骤,把实现延迟到子类. 事实上模板模 ...