Android应用程序窗口设计之Window及WindowManager的创建

2024-04-13 00:38

本文主要是介绍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的创建的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/898681

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

顺序表之创建,判满,插入,输出

文章目录 🍊自我介绍🍊创建一个空的顺序表,为结构体在堆区分配空间🍊插入数据🍊输出数据🍊判断顺序表是否满了,满了返回值1,否则返回0🍊main函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞+关注+评论+收藏(一键四连)哦~ 🍊自我介绍   Hello,大家好,我是小珑也要变强(也是小珑),我是易编程·终身成长社群的一名“创始团队·嘉宾”