首先介绍下什么是启动窗口,对于大部分应用冷启动时的场景都会有启动窗口,为了让效果更明显,在如下代码中(只是一个基本的可以运行的应用即可)添加了sleep5s的代码,在按recent键移除应用后,再点击桌面图标,即可看到启动窗口效果,即使点击后界面内容显示出来前的白色界面
image-20200627223615053.png1596117549969.gif
启动窗口有什么用途呢,从逻辑及效果看,其应该主要是用于一个过渡,比如上述添加了5s延时的场景中,如果没有启动窗口,那么点击了桌面的应用图标后,会有5s多的时间用户看不到什么反应,会让用户觉得是不是应用没启动啊,我们可以试验下,可在style中添加
<item name="android:windowDisablePreview">true</item>
项,即可禁用启动窗口,如
image-20200627224321594.png
对用户和应用来说一个白色界面作为启动窗口可能不是很美观,也可以做一些自定义行为
1、一般需要较长时间加载的应用启动窗口的作用更明显,所以可以实现个简单的Activity作为欢迎界面,待准备工作加载完成后,即可跳转到正式界面
2、启动窗口界面内容本身有配置的方法,可通过配置
<item name="android:windowSplashscreenContent"> </item>
项来设置启动窗口的内容界面,显然这里可设置一个drawable,在添加启动窗口界面时,会将该drawable添加到启动窗口的内容视图中,如
1596117876257.gif
另外可通过设置<item name="windowAnimationStyle"> </item>来设置相关动画,这里就不举例了
添加启动窗口代码逻辑(使用android-10.0.0_r39分支代码查看)
(添加时机,一般是前台task切换时可能会触发,比较特别地是一般新启动一个应用,或杀掉一个应用进程后启动该应用时,这种情况下一般都会有启动窗口,如设置、电话等应用新启动时,会先显示一个空白的界面,然后显示设置界面内容,那个空白的界面即其启动窗口)
ActivityRecord.java-showStartingWindow
image-20200627224821300.png在这里会调用其addStartingWindow方法(ActivityRecord)
image-20200627225544058.png显然,这里主要是调用了AppWindowToken的addStartingWindow方法,查看AppWindowToken的addStartingWindow方法,这里逻辑稍多,介绍下其主要部分
1、该方法中会调用getStartingWindowType方法根据场景获取需要启动窗口类型
image-20200627225858187.png其中AppWindowToken的getStartingWindowType方法逻辑如下
image-20200627230030337.png从上述代码可知getStartingWindowType方法可能返回三种值 STARTING_WINDOW_TYPE_NONE,STARTING_WINDOW_TYPE_SPLASH_SCREEN ,STARTING_WINDOW_TYPE_SNAPSHOT
返回类型为STARTING_WINDOW_TYPE_NONE时看其逻辑应该是无启动窗口的
返回类型为STARTING_WINDOW_TYPE_SPLASH_SCREEN时即可能会有场景中的启动窗口,比如在杀掉设置进程后(点击recent导航键,移除设置),点击设置图标后马上dumpsys window信息可看到有如下窗口,这就是启动窗口的窗口,也是这里主要介绍的逻辑(如下是设置的启动窗口)
image-20200627230345034.png返回类型为STARTING_WINDOW_TYPE_SNAPSHOT时,会调用createSnapshot方法,这里也会临时添加一个特殊的窗口,比如进入设置后,回到桌面,点击recent导航键,然后点击,这里就不细将了
image-20200627230604007.png2、如果theme中设置了windowIsTranslucent为true,或者设置了windowIsFloating为true,或者设置了windowDisablePreview为true,则不会添加启动窗口
image-20200627230838390.png3、AppWindowToken的addStartingWindow方法的主要逻辑会创建一个SplashScreenStartingData对象,然后调用scheduleAddStartingWindow方法
image-20200627231001578.pngAppWindowToken的addStartingWindow方法就到这里了,继续跟踪其主要逻辑
scheduleAddStartingWindow方法主要是将一个mAddStartingWindow任务放到一个handler队首去执行
image-20200627231135203.png再看下mAddStartingWindow的逻辑:
image-20200627231354809.png这里mStartingData即是前面addStartingWindow中创建的SplashScreenStartingData对象(只针对这里STARTING_WINDOW_TYPE_SPLASH_SCREEN的情况),这里主要逻辑即调用SplashScreenStartingData的createStartingSurface方法
image-20200627231547302.png显然,SplashScreenStartingData的createStartingSurface方法中调用了PhoneWindowManager的addSplashScreen方法而PhoneWindowManager的addSplashScreen方法也即是添加启动窗口的地方
image-20200627231806108.png image-20200627231853737.png image-20200627231958425.png image-20200627232221316.png如上即是PhoneWindowManager的addSplashScreen方法的代码,其主要部分就是创建一个PhoneWindow对象,然后设置些属性和视图(基本上应该是全屏,内容应该是根据theme相关只有框架的界面,具体内容一般为空白,有的有图标和标题),然后调用WindowManager服务的addView方法添加窗口
这里也有几个可设置相关属性的地方
1、windowAnimationStyle
image-20200627232535987.png应该可以通过设置windowAnimationStyle设置相关动画
2、windowSplashscreenContent
image-20200627232650202.png根据启动窗口调用的addSplashscreenContent方法,应该可以通过设置windowSplashscreenContent属性来设置启动窗口的内容图片
在添加启动窗口呼,待合适的时机,如应用界面绘制完成则会触发AppWindowToken的removeStartingWindow方法调用,然后移除启动窗口,这里就不细述了
网友评论