本文主要是介绍Android应用程序窗口设计之Window及WindowManager的创建,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Android应用程序窗口设计之Window及WindowManager的创建
Android应用程序窗口设计系列博客:
Android应用程序窗口设计之Window及WindowManager的创建
Android应用程序窗口设计之setContentView布局加载的实现
普法Android的Token前世今生以及在APP,AMS,WMS之间传递
Android应用程序窗口设计之窗口的添加
Android应用程序窗口设计之建立与WMS服务之间的通信过程
Android窗口设计之Dialog、PopupWindow、系统窗口的实现
Android应用程序建立与AMS服务之间的通信过程
本篇博客编写思路总结和关键点说明:
为了更加方便的读者阅读博客,通过导读思维图的形式将本博客的关键点列举出来,从而方便读者取舍和阅读!
引言
经过前面系列博客Android四大组件之Activity启动流程源码实现详解的艰苦卓越的奋斗的成果,我们终于将Activity的启动流程分析得妥妥当当了。在前面的博客中完成了Activity的创建以及相关它的生命周期的调度,但是上述的相关的分析的重心是Activity的启动流程却并没有涉及到Activity的核心用途作为展示窗口的实现原理和流程,我们知道Activity当初被谷歌的设计的初衷就是作为Android的颜值担当呈现出各种缤纷多彩的UI界面,而上述的一切都离不开Activity对各种布局的加载和显示了(这个站在Android的设计者的角度出发就是Android应用程序窗口的设计了),这不就给安排上了,在今天的博客以及后续的博客中将会分析Android应用程序窗口设计的实现,而我们知道Android应用程序窗口的相关载体就是我们的Activity了,所以本篇即以后的相关篇章中涉及到的Android应用程序的窗口实现我们会以Activity为例来说,而Activity相关的窗口概念中设计的最最重要的就是Activity的布局加载和绘制等相关流程了。
而大家也知道在Android体系中Activity扮演了一个界面展示的角色,这也是它与Android中另外一个很重要的组件Service最大的不同,那么大家有没有过如下的相关思考呢:
- Activity是如何控制界面的展示呢,是一人操持整个流程,亦或者是各个服务通力协作?
- 界面的布局文件是如何加载并被管理的呢,是被Activity直接管理,亦或者是有第三方协助?
- Android中的View/Window/WindowManager是一个怎样的概念,它和Activity是怎么关联起来的?
- 被加载好的布局文件是怎么显示出来的?
要回答上述疑问,是没有办法一蹴而就的,只能说是路漫漫而修远吾将上下而求索!但是有一点我们可以确认的就是上述疑问归根究底就是Android是怎么处理Activity中界面加载与绘制流程的(往大了,也可说是Android是怎么处理界面布局加载和绘制)!我们可以先对上述问题逐个分解,一一突破,而我们这里先分析Activity中界面布局的加载流程,在分析的过程中对于上述问题的答案就会跃然纸上了!
注意:本篇的介绍是基于Android 7.xx平台为基础的,其中涉及的代码路径如下:
frameworks/base/core/java/com/android/internal/policy/--- DecorView.java--- PhoneWindow.javaframeworks/base/core/java/android/view/--- WindowManager.java--- View.java--- ViewManager.java--- ViewRootImpl.java--- Window.java--- Display.java--- WindowManagerImpl.java--- WindowManager.java--- WindowManagerGlobal.java--- IWindowManager.aidlframeworks/base/services/core/java/com/android/server/pm/--- PackageManagerService.javaframeworks/base/services/core/java/com/android/server/wm/WindowManagerService.javaframeworks/base/core/java/android/content/pm/--- ActivityInfo.javaframeworks/base/core/java/android/app/--- IActivityManager.java--- ActivityManagerNative.java (内部包含AMP)--- ActivityManager.java--- AppGlobals.java--- Activity.java--- ActivityThread.java(内含AT)--- LoadedApk.java --- AppGlobals.java--- Application.java--- Instrumentation.java--- IApplicationThread.java--- ApplicationThreadNative.java (内部包含ATP)--- ActivityThread.java (内含ApplicationThread)--- ContextImpl.java--- SystemServiceRegistry.java
且在后续的源码分析过程中为了简述方便,会将做如下简述:
- WindowManagerService简称为WMS
- ActivityManagerService简称为AMS
在正式开始本篇博客Activity中界面布局的加载流程分析之前,这里有必要先将Activity、View、Window、WindowManager之间的类图关系先放出来,以便能够方便后续的相关阅读,使读者能够更加清楚的知道这几者之间在源码中的关系。
关于上述几个之间的关联,恩怨情仇我们有必要提前捋一捋。
我们知道通常Android应用程序里所有的界面展示都来自于Activity,但是Activity的力量是薄弱的并不来独自完成整个界面的展示,这就需要Activity、View、Window、WindowManager的各司其职,更加需要它们之间的通力合作来完成这一历史重任,向用户展示各种绚丽多样的界面了。
Activity:它应该是我们开发者最熟悉的一个组件了,对于开发者来说所有的界面展示都来自于Activity,但是对于用户来说他们不管你是啥(在用户眼里只有界面和交互的概念),所以我个人认为Activity当初被设计只是用来给开发者来承载各种界面布局,有点像幕后英雄或者是总设计师的感觉(因为是以它的意愿为基础加载各种布局来呈现给我们的用户)。
Window:在界面加载和布局中,Actiivty是一个比较抽象的概念,它是Android为了方便我们开发者开发而提出的,其实Activity对界面布局的管理是都是通过Window对象来实现的,Window对象,顾名思义就是一个窗口对象,而Activity从用户角度就是一个个的窗口实例,因此不难想象每个Activity中都对应着一个Window对象,而这个Window对象就是负责加载界面的。
View:我们知道Android的每个应用中的每个界面基本都是不一样,即window对象给我们展示的都是不同的界面,那么是如何做到这一点的呢,这就需要我们的各种View组件上场了,通过各种View组件的排列组合搭积木般的实现了千人千面的的界面展示效果。
WindowManager:通过上述三者之间的通力协作终于完成了我们布局文件的加载了,但是加载完成这还远远远不够,因为我们最终的目标是呈现给用户,这就轮到我们的WindowManager上场了。通过它我们和WMS之间建立了关联,进而将上述Window送到surfaceflinger中进行相关的渲染显示,并最终呈现给我们用户。
一. Activity布局加载前期准备
前面整了这么一大堆,读者没有感到啰嗦我都觉得有点啰嗦和废话了!但是吗,有时候不来点前戏,直入主题又有点突兀(各位此段不是开车,真不是开车),让人难以理解,这个各位见仁见智吗!通过前面一系列的博客我们知道,在startActivity()后,经过一些逻辑流程会通知到system_server进程的AMS服务,AMS接收到启动Activity的请求后(无论是冷启动目标Activity还是热启动目标Activity),最后都会通过跨进程通信调用AcitivtyThread.handleLauncherActivity()方法,我们从这里开始分析。注意我们这里只重点关注和Activity布局加载相关的逻辑代码,至于目标Activiyt启动和生命周期相关执行的代码就不是这里的博客重点关注的,因为我们在前面的博客Activity启动流程(七)- 初始化目标Activity并执行相关生命周期流程中已经有重点关注过了!
1.1 ActivityThrread.handleLaunchActivity(…)
//[ActivityThread.java]private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {... WindowManagerGlobal.initialize();//这个方法的实质是获取WMS服务代理端...Activity a = performLaunchActivity(r, customIntent);//创建目标Activity,并创建Activity对应的Window,详见章节1.2...if (a != null) {//此方法最终会调用到Activity的onResume()方法中handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);}... }
handleLaunchActivity方法中有三个我们需要重点关注的点:
- 首先就是WindowManagerGlobal.initialize()方法,WindowManagerGlobal是单例模式的,一个进程内只有一个,这里调用该类的initialize初始化方法,获取WMS服务的代理端
- 接着调用performLaunchActivity方法,从而创建目标Activity,并创建Activity对应的Window,这个我们会在后面章节详细的分析
- 最好调用handleResumeActivity方法,进而执行目标Activity的onResume方法,这个也后面详细分析
这里我们先看看WindowManagerGlobal.initialize()方法的实现,代码如下:
//[WindowManagerGlobal.java]private static IWindowManager sWindowManagerService;public static void initialize() {getWindowManagerService();}public static IWindowManager getWindowManagerService() {synchronized (WindowManagerGlobal.class) {if (sWindowManagerService == null) {sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));try {sWindowManagerService = getWindowManagerService();ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}return sWindowManagerService;}}
可以看到上述方法比较简单,就是通过一个单例模式获取WMS的代理端,进而为Activity目标进程和WMS的通信打下基础!这里我们只需注意一下IWindowManager的类图关系,正是由于它的存在所以才具备了跨进程和WMS服务Binder通信的能力。
1.2 ActivityThrread.performLaunchActivity(…)加载Activity以及对应的Window窗口
这里我们只重点关注和Activity布局加载相关的源码,关于其它的可以参见博客Activity启动流程(七)- 初始化目标Activity并执行相关生命周期流程中的章节2.3有详细的介绍(在这里只会一笔带过)。
//[ActivityThread.java]private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {//开始构建目标Activity相关信息...Activity activity = null;try {/*通过反射加载目标Activity这里获取的ClassLoader是前面博客已经初始化了的*/java.lang.ClassLoader cl = r.packageInfo.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);...} catch (Exception e) {...}try {/*创建目标Actiivty应用进程Application,目标Application在前面博客中已经有被创建了,而且应用进程的Application是唯一的,所以会直接返回前面创建的Applcation*/Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (activity != null) {//创建目标Activity对应的Context上下文Context appContext = createBaseContextForActivity(r, activity);...Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {//此种情况即复用以前的Windowwindow = r.mPendingRemoveWindow;r.mPendingRemoveWindow = null;r.mPendingRemoveWindowManager = null;} //将上述创建的相关信息,attach到Activity中为后续Activity显示运行做准备,详见1.3 activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window);...activity.mCalled = false;//这个地方是干啥的呢,防止开发者在执行onCreate()方法的时候没有初始化父类Activity的onCreate()方法//开始执行目标Activity的onCreate()方法回调if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}...} catch (SuperNotCalledException e) { throw e;} catch (Exception e) {...}return activity;}
上述方法在这里我们只关心两点:
- 通过传递进来的ActivityClientRecord信息,通过反射创建目标Activity实例对象。
- 然后调用目标Activity的实例对象的attach()方法(这个方法,在前面的博客中我们只是简单的一笔带过,但是在这个博客中是重中之重需要重点分析)。这里我们可以看到attach传入的参数非常非常多,毫不夸张的说我们在performLacunchActivity()方法以及更前面的一系列调用方法中,绝大部分工作都是为了填充ActivityClientRecord的信息而做的,待ActivityClientRecord的信息填充饱满以后借用attach()方法将这些参数配置到新创建的Activity对象中,从而将目标Activity和我们的应用进程,甚至是AMS等关联起来。
这里我们还可以看到,在attach之前可能会初始化一个Window实例对象,即如果ActivityClientRecord.mPendingRevomeWindow变量中已经保存了一个Window对象,则会在后面的attach方法中被使用,具体使用的场景会在后面中介绍。
这里的Window是一个抽象类,它实现了对Activity的布局的管理,从而负责加载显示界面,并且每个Activity都会对应了一个Window对象。
1.3 Activity.attach(…)为Activity附加应用进程相关信息以及创建目标Window
此时目标Activity以及相关所需要的对象都创建好了,就需要将Activity和Application对象、ContextImpl对象绑定在一起,并且创建目标Activity对应的Window窗口了。并且我们还需要知道上述的几个之间在Activity应用进程之间存在着如下的关联(至于具体的解释,详见博客Activity启动流程(七)- 初始化目标Activity并执行相关生命周期流程的第三大章节)。
//[Activity.java]final void attach( Context context, //目标Activity对应的Context上下文信息,即前面创建的ContextImpl实例对象ActivityThread aThread,//Activity应用进程的主线程ActivityThread实例对象Instrumentation instr, //监控管理Activity运行状态的Instrumentation实例对象IBinder token, //这个token是啥呢,用于和AMS服务通信的IApplicationToken.Proxy代理对象,它对应的实体是在AMS为目标Activity创建对应的ActivityRecored实例对象的时候创建的int ident,Application application, //Activity应用进程对应的Application实例对象Intent intent, ActivityInfo info,//Activity在AndroidManifest中的配置信息CharSequence title, Activity parent, //启动当前Activity对应的ActivityString id,NonConfigurationInstances lastNonConfigurationInstances,Configuration config, String referrer, IVoiceInteractor voiceInteractor,Window window //是否存在可以复用的Window) {//将前面创建的上下文对象ContextImpl保存到Activity的成员变量中attachBaseContext(context);//这个应该和Fragment有关系,这个不在我们本篇博客的关注范围之内,所以让我们大声的说passmFragments.attachHost(null /*parent*/);//此处是重点,直接以PhoneWindow实例Window窗口对象mWindow = new PhoneWindow(this, window);//详见章节1.4mWindow.setWindowControllerCallback(this);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {mWindow.setSoftInputMode(info.softInputMode);}if (info.uiOptions != 0) {mWindow.setUiOptions(info.uiOptions);}//记录记录应用程序的UI线程mUiThread = Thread.currentThread();//记录应用进程的ActivityThread实例mMainThread = aThread;mInstrumentation = instr;mToken = token;mIdent = ident;mApplication = application;mIntent = intent;mReferrer = referrer;mComponent = intent.getComponent();mActivityInfo = info;mTitle = title;mParent = parent;...//初始化其它的相关Actiivty成员变量//为Activity所在的窗口设置窗口管理器,详见章节1.5,并且这里的setWindowManager没有被重构,直接调用的是父类Window的方法mWindow.setWindowManager((WindowManager)context.getSystemService(Context.WINDOW_SERVICE),mToken, mComponent.flattenToString(),(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);if (mParent != null) {mWindow.setContainer(mParent.getWindow());}//保存窗口管理器实例对象mWindowManager = mWindow.getWindowManager();mCurrentConfig = config;}
在我们哼哧哼哧进行相关的源码分析前,我们有必要来理一理attach的入参参数(不知道小伙们有没有发现,反正Android源码中一些方法或者函数的入参经常是一大把一大把的)!
参数类型 | 参数名称 | 参数功能 |
---|---|---|
Context | context | 目标Activity对应的Context上下文信息,即前面创建的ContextImpl实例对象 |
ActivityThread | aThread | Activity应用进程主线程ActivityThread实例对象 |
Instrumentation | instr | 监控管理Activity运行状态的Instrumentation实例对象,它在整个进程中也是唯一的 |
IBinder | token | 这个token是啥呢,它是被用于和AMS服务通信的IApplicationToken.Proxy代理对象,它对应的实体是在AMS为目标Activity创建对应的ActivityRecored实例对象的时候创建的 |
Application | application | Activity应用进程对应的Application实例,它在整个进程中是唯一的 |
Activity | activity | 启动当前目标Activity的Activity |
Window | window | 表示当前Activity是否存在可以复用的Window |
… | … | … |
好了入参的参数我们捯饬清楚了,是时候进入正题分析attach方法的主要逻辑了,它干了如下几件事情:
- 为Activity创建对应的Window实例对象,并且这里的Window类型直接点明了为PhoneWinow,此处为Activity和Window之间的关联正式建立了!并且我们后续会知道Activity中很多操作View相关的方法,例如setContentView()、findViewById()、getLayoutInflater()等,实际上都是间接调用到PhoneWindow里面的相关方法的,这样是为什么说Window是布局的管理类了
- 根据掺入的参数初始化Activity相关的成员变量
- 为上述创建的Window实例对象创建窗口管理器(注意一定要和WMS的客户端代理区分清楚,千万不要搞错了)
至此我们为Activity已经初始化了各种实例对象了,并且他们之间存在着如下的关联关系:
1.4 应用进程Activity窗口Window创建流程
在分析Activity窗口怎么建立之间,我们先看看Activity所谓窗口Window的关系图如下:
Window从语义上翻译就是窗户,窗口的意思,放在现实世界中都是很具体的物件。而我们这里的Window是一个抽象的类,并没有继承任何View或者实现View,并且其子类也是如此!记得我刚开始学习关于Android应用进程窗口相关的概念是老是转弯不过来,总是感觉这里的Window好空洞啊,是不是翻译或者起的名字有问题和现实世界关联不起来啊!
那么我们应该怎么理解这里的Window窗口的概念呢,先看看来可以从如下两点入手:
1.读者可以这么认为这个是Android的设计者人为而设计的用来管理Activity布局的一个管理类,且它的类名恰好叫做Window而已,并且在Android相关的知识传播过程中将这里的Window统称为窗口了(并且我们在后续的分析中会知道Activity真的和窗口显示相关的是DecorView)。
2.Activity的各种布局确实需要在Android给我们的划定的Window中进行各种操作,至少在这个层面说此Window被叫做窗口也不为过
以上的是我的个人理解,总之至少中国的Android界是这么约定俗成的叫着,至于具体怎么理解小伙们就看各位小伙们了。网上也有的博客将Window理解为现实世界的窗户,各种View理解为窗花,这个就仁者见仁,智者见智各自理解吗!
好了前面扯了一堆我对Activity中窗口概念的理解,是时候看看Activity中的窗口是怎么被构建出来的了!
//[PhoneWindow.java]public PhoneWindow(Context context, Window preservedWindow) {this(context);mUseDecorContext = true;//注意此处,这个点后续会用到if (preservedWindow != null) {//重点要理解的是此处mDecor = (DecorView) preservedWindow.getDecorView();mElevation = preservedWindow.getElevation();mLoadElevation = false;mForceDecorInstall = true;getAttributes().token = preservedWindow.getAttributes().token;}boolean forceResizable = Settings.Global.getInt(context.getContentResolver(),DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;mSupportsPictureInPicture = forceResizable || context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE);}
这里的PhoneWindow构造方法看似平淡无奇,但是这里我们需要重点关注的就是preserviedWindow参数(从英文字面意思直译过来就是已经被保存的窗口),从调用的流程来看这个参数最终来自于前面章节1.2中所提到的mPendingRevomeWindow变量,也许读者会有一个疑问这个参数在什么时候会不为空呢?其实这里的逻辑是用来快速重启Acitivity的,比如你的一个Activity已经启动了,但是主题换了或者configuration变了,这里只需要重新加载资源和View,没必重新再执行DecorView的创建工作(关于这块,我们可以在源码分析中暂且忽略)。
另一个要关注的就是mDecor变量,这个变量是DecorView类型的(它,我们这里暂且不过多分析,后续会专门分析它),如果这里没有初始化的话,则会在调用setContentView方法中new一个DecorView对象出来。DecorView对象继承自FrameLayout,所以他本质上还是一个View,只是对FrameLayout做了一定的包装,例如添加了一些与Window需要调用的方法setWindowBackground()、setWindowFrame()等。我们知道,Acitivty界面的View是呈树状结构的,而mDecor变量在这里作为Activity的界面的根View存在。关于这三者之间的关系如果一定要找到现实世界中的映射,那么PhoneWindow就是我们经常在电梯中看到的电子广告屏,DecorView就是电子广告屏要显示的内容,而Activity就是控制电子广告屏要具体显示什么的神秘幕后的操盘手了。
1.5 创建应用进程Activity窗口管理器
好了经过我们前面一阵捣鼓,我们的Activity的窗口对象PhoneWindow也建立了,而且通过前面章节1.3的分析可知有了窗口Android必不会对其放任自流不管,紧接着会指定一个窗口管理器来管理这些窗口,因此在Activity启动过程中还会创建一个WindowManager对象来管理上述的窗口,我们接着看看这个窗口管理器是何方妖怪,吃我老孙一棒!
并且在进行相关的分析前,我们先来看看WindowManager的类图关系,注意它们是接口类,注意注意注意!
//[Window.java]private WindowManager mWindowManager;public void setWindowManager(WindowManager wm, IBinder appToken, String appName,boolean hardwareAccelerated) {mAppToken = appToken;// IApplicationToken.Proxy代理对象mAppName = appName;mHardwareAccelerated = hardwareAccelerated|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);if (wm == null) {wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);}mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);}
setWindowManager方法的入参有一个需要注意的就是wm,这里的wm从前面的章节知道它是通过调用如下方式获取到的,如下:
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE)
根据Context的类图关系我们可知,上述方法最终会调用到ContextImpl中去,执行如下的逻辑:
//[SystemServiceRegistry.java]@Overridepublic Object getSystemService(String name) {return SystemServiceRegistry.getSystemService(this, name);}registerService(Context.WINDOW_SERVICE, WindowManager.class,new CachedServiceFetcher<WindowManager>() {@Overridepublic WindowManager createService(ContextImpl ctx) {return new WindowManagerImpl(ctx);}});
上面的相关逻辑就不展开了,总之获取到的是以Activity对应的Context上下文构建的WindowManagerImpl对象实例!
好了重要的入参我们捯饬清楚了,我们接着来分析分析setWindowManager方法干了些啥,可以看到它主要是实例化了wWindowManager变量。它实例化的前提是将前面传递过来的参数wm强制转换为WindowManagerImpl,然后调用createLocalWindowManager(),在createLocalWindowManager()实际是执行了一个new WindowManagerImpl()方法来创建。
关于这部分代码本人存在一个很大的疑惑点,就是为啥Android当初要把这个地方涉及的这么复杂呢,其实传递过来的wm已经是一个WindowManagerImpl类型的实例了,这里createLocalWindowManager()重新创建一个实例,不过是使用了前面传递过来的wm的成员变量mContext,然后加上此时PhoneWindow自己的this指针而已!
直接使用传递过来wm,然后添加一个方法将PhoneWindow传递过去就可以这样不香吗,反而多此一举再new一个呢!
//[WindowManagerImpl.java]private WindowManagerImpl(Context context, Window parentWindow) {mContext = context;mParentWindow = parentWindow;}public WindowManagerImpl createLocalWindowManager(Window parentWindow) {//注意这里的parentWindow是我们前面创建的PhoeWindowreturn new WindowManagerImpl(mContext, parentWindow);}
注意此处的parentWindow指向了Activity对应的PhoneWindw窗口,这个地方需要注意,后续我们会用到!
至此我们为Actiivyt的窗口创建了了窗口管理器WindowManagerImpl,并且它保存了对于单例对象WindowManagerGloble的引用,即mGlobal变量。此外,通过前面我们的类图可以看到WindowManagerImpl实现了WindowManager,并且WindowManager继承自ViewManager接口,ViewManager接口方法如下所示(可以看到它定义的接口方法都是和View有关系的):
//[ViewManager.java]
public interface ViewManager
{public void addView(View view, ViewGroup.LayoutParams params);public void updateViewLayout(View view, ViewGroup.LayoutParams params);public void removeView(View view);
}
分析到这里我们发现我们Activity直接持有WindowManagerImpl,然后通过WindowManagerImpl间接持有WindowManagerGloble,并且WindowManagerGloble在整个应用进程中是唯一的(因为它采用了单例模式)。至此我们可以得出一个结论就是Android系统为每一个启动的Activity创建了一个轻量级的窗口管理器WindowManagerImpl,每个Activity通过WindowManagerImpl来访问WindowManagerGloble,并且Activity中关于窗口的相关操作最后都是由mGlobal亲自操刀的,它们三者之间的关系如下图所示:
小结
本来是打算将Activity布局加载流程实现详解放在这篇博客中,一网打净的!但是,但是读者也看到了,到此还只是进行了Activity布局加载前期准备就已经有了这么多的内容了,所以为了阅读方便只能将此部分分系列进行了!
这里我们还是按照老规矩,先来对前面的知识总结一番,在本篇章节中我们重点分析到了:
- 通过前面一系列启动Activity的前期工作获取到的Activity信息,然后通过反射创建了我们的目标Activity
- 接着调用目标Activity的attach方法,将启动Activity的相关信息初始化它的成员变量
- 然后在attach方法中,创建Activiyt对应的窗口Window(这里建议读者重点理解理解Window窗口的概念)
- 接着为创建的Window窗口设置窗口管理器WindowManagerImpl
其整个流程可以通过如下的伪代码来表示:
AT.handleLaunchActivity(...) --->
AT.performLaunchActivity(...) --->
通过反射创建目标Activity(new Activity()) --->
创建Context上下文 --->
Activity.attach(...) --->ContextImpl绑定创建PhoneWindow创建WindowManager管理器
Activity.onCreate() --->setContentView(...) --->
至此,经过上述的努力我们Activity布局加载流程实现详解的前期准备工作已经做好了,窗口已经准备了,窗口管理器也已经准备好了,就等Activity在我们的窗口上任意创作需要显示的界面了,然后加载到我们的WIndow窗口中进行显示了。而上述未完成的任务也是我们后续博客将要重点分析的了。
写在最后
Android应用程序窗口机制之Window及WindowManager的创建这里就要告一段落了,Activity布局加载流程的准备工作也已经就绪了,作画的窗口,亦或者是要展示广告的电子屏已经备好就等Activity来尽情挥洒墨水创作了。在接下来的博客中,我将会重点分析目标Activity的是怎么加载布局以及怎么将布局绘制到我们的终端界面上面的,如果有感兴趣的亲请期待。好了,青山不改绿水长流先到这里了。如果本博客对你有所帮助,麻烦关注或者点个赞,如果觉得很烂也可以踩一脚!谢谢各位了!!
这篇关于Android应用程序窗口设计之Window及WindowManager的创建的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!