应用窗口创建

一、创建Window对象

每个应用类窗口window都对应于一个Activity对象。创建应用类窗口都需要先去创建一个Activity。

AmS决定启动Activity时会先通知客户端进程,每个客户端进程都对应于一个ActivityThread对象,启动Activity任务最后由ActivityThread完成。

android getLaunchIntentForPackage 需要权限么 android getwindow_android


以上是Window创建过程,简单总结如下。

1.ActivityThread收到AMS启动Activity请求,首先调用到ActivityThread.newActivity()方法,在该方法中根据类名反射生成目标Activity对象。

2.接着调用Activity.attach()方法。

(1) 在该方法中主要是做变量赋值以及最重要的调用PolicyManager.makeNewWindow()生成一个Window对象,而此处其实就是PhoneWindow对象,同时会在其PhoneWindow内部生成WindowManager.LayoutParams对象,而该对象内部type变量标示该Window类型,默认就是Application类型即应用程序窗口。

(2) 为生成的window对象设置事件回调即Activity对象,这样Window可以和Activity通信。

(3) 为生成的window对象设置WindowManager对象,其实就是创建一个WindowManagerImpl对象,该对象负责管理Window中的View。WindowManagerImpl内部是一个WindowManagerGlobal类型的单例引用,所有操作实现最后交给该引用完成。赋值WindowManager到Activity内部。

注意:参数mToken传递。该参数原型时AmS中的HistoryRecord对象,由AMS传递创建Activity使用。它既是Activity的唯一标示,也是创建Window后的唯一标示。

android getLaunchIntentForPackage 需要权限么 android getwindow_Window创建_02

二、为Window添加View

android getLaunchIntentForPackage 需要权限么 android getwindow_android_03

为window添加内容是开发者在Activity生命周期函数onCreate()中使用setContentView()设置的。

简单总结如下:

1.Activity生命周期函数onCreate()中使用setContentView(),在该函数中实际调用到attach()中生成的PhoneWindow.setContentView(),接着会调用initActionBar()初始化ActionBar。

2.在PhoneWindow.setContentView()函数中

(1)先判断mContentParent是否为null,mContentParent是真正放置Window内容的FrameLayout,其id固定为@android:id/content,开发者指定的layout.xml就是添加到这个Layout中显示的。如果为null代表还没初始化这个PhoneWindow执行installDecor(),不为null直接remove已加载的View。

(2)执行installDecor(),首先判断如果mDecor为null就去新建对象DecorView。DecorView其实就是继承自FrameLayout的大小为整个屏幕的ViewGroup,他是PhoneWindow的顶级ViewGroup,所有的View最终根元素就是它。接着又判断mContentParent是否为null,如果是则调用generateLayout()加载Window装饰器layout,而Window装饰器Layout=mContentParent+Window顶部装饰(ActionBar/TitleBar)。

(3)generateLayout()通过读取配置设置Window的FLAG特征,以及根据开发者配置加载装饰器Layout。获取到指定的装饰器Layout的id之后inflate得到View,使用DecorView将其添加。接着可以获取mContentParent,不论是何种装饰器Layout都有存在固定id为@android:id/content的FrameLayout,用来加载开发者指定的Layout。

这里的开发者配置有两个途径:

  • 在Activity的onCreate()方法中获取Window对象调用requestFeature()设置,在generateLayout()中使用getLocalFeature()获取。
  • 在AndroidManifest.xml中为Activity使用android:theme=”“,在generateLayout()中使用getWindowStyle()获取。

(4)通过上步可以获取到用户需要的ActionBar或者TitleBar,开始设置其对应属性。至此installDecor()函数执行完成。

(5)通过以上初始化mContentParent、mDecorView完毕,接着就加载开发者指定的layout到mContentParent中,同时回调Activity中的函数实现。

3.最后调用Activity.initActionBar()初始化ActionBar。

以上就是应用类窗口添加View的过程。

android getLaunchIntentForPackage 需要权限么 android getwindow_android_04

android getLaunchIntentForPackage 需要权限么 android getwindow_android_05

三、添加显示Window

android getLaunchIntentForPackage 需要权限么 android getwindow_Layout_06

在经过了创建Window对象,为Window添加View之后就是告诉WmS添加显示Window。

当Activity准备显示Window时会通知AmS,经过一系列调用到Activity.makeVisible()。

在makeVisible()方法中:

1.首先获取Activity内部的WindowManager对象wm。

2.接着调用wm的addView(),其真正实现在WIndowManagerImpl中,在该类中又真正调用到的是WindowManagerGlobal.addView()。而WindowManagerGlobal是个单例模式类,内部维护三个数组用于保存该应用程序中所拥有的窗口状态,分别是:

  • View[] mViews。即Window的定级View
  • ViewRoot[] mRoots。即ViewRootImpl对象,mViews中每个View都对应一个ViewRootImpl对象。该对象负责Window的View所有操作。
  • WindowManager.LayoutParams[] mParams。每个Window对应一个布局参数。

3.在WindowManagerGlobal.addView()主要是三个步骤

(1)查找是否已经添加过该窗口,不允许重复添加

(2)判断是否是一个子Window如果是查找其父Window的View赋值给panelParentView。

(3)创建ViewRootImpl对象,调用其setView()方法完成真正添加

4.在ViewRootImpl.setView()中通过常量mWindowSession类型为IWindowSession,通知WmS添加该这个窗口,传入的是ViewRootImpl内部类W继承自android.view.IWindow.Stub。

PhoneWindow充当一个临时变量角色管理DecorView,其实真正通知WmS添加的是W。