文章目录
概述
我们在很多APP启动的时候都能看到一闪而过的黑屏或者白屏,在我们这些强迫症深度患者看来,确确实实是个很糟糕的体验。但是在我们打开QQ或者一些优化过的应用的时候却看不到所谓的黑屏或白屏。我们今天就来探讨下这个黑白屏启动优化
历史
在最早的Android机器上, 点击需要一定的时间来响应,然后启动。但是在这 App 未完全启动的时候,用户不能明确 App 是否已经启动,为了解决这个用户体验的问题,特意加上了启动黑白屏来表示 App 已经启动。
但是解决了点击无反应的问题,又出现了黑白屏体验不好的问题,方法总比问题多,有的应用设置背景为透明,有的应用放置图片,总之各有妙招
黑白屏出现原因
当我们设置下面主题属性时,会出现首次启动白屏或者黑屏的问题
白屏 <style name="AppTheme" parent="Theme.AppCompat.Light">
黑屏 <style name="AppTheme">(在以前的老版本上有效,现在的版本默认使用透明处理了)
我们点击Theme.AppCompat.Light
一直追溯,找到一个父类name="Platform.AppCompat.Light"
中定义了
<item name="android:windowBackground">
用来控制黑白屏,我们能从下面图中看到windowBackground被设置为@color/background_material_light
当从launcher
启动一个APP时,需要fork一个进程并进行一些初始化,而fork进程和初始化是需要时间的,这时候就有了StartingWindow
(也称之为PreviewWindow
)的出现,
StartingWindow
一般出现在应用程序进程创建并初始化成功前,所以它是个临时窗口,对应的WindowType
是TYPE_APPLICATION_STARTING
。目的是告诉用户,系统已经接受到操作,正在响应,在程序初始化完成后实现目的UI,同时移除这个窗口
我们看到windowBackground
这个属性设置的值就是为这个StartingWindow
服务的,设置黑屏主题就会显示黑屏,设置白屏主题就会显示白屏,设置一张图片就会显示一张图片
Android系统架构
我们作为上层开发者,理解Android架构便于我们更好的优化我们的应用,下面开始我们的性能优化之路
像Android开源和兼容性技术负责人Dan Morrill在Android开发手册兼容性部分所解释的,“Android并不是传统的Linux风格的一个规范或分发版本,也不是一系列可重用的组件集成,Android是一个用于连接设备的软件块。如果在真个Android系统生态来看的话,我们设计编写的应用只是作为上层的展示,仅仅是整个生态中最表面的一块,用一个通俗的说法就是应用只是一个我们成为的APK的压缩文件,他大体内容页如下图所示
Android是基于Linux的一个操作系统,它可以分为五层,下面是它的层次架构图,可以记一下,因为后面应该会总结到SystemServer这些Application Framework层的东西
App启动流程
下面该图是阿里公众号里找的一个图,大致描述了Android系统的启动流程,图上标识的数字跟下面的介绍没有关系,仅供参考
下面详细介绍具体启动流程
-
打开电源 引导芯片代码加载引导程序Boot Loader到RAM中去执行
-
BootLoader把操作系统拉起来
-
Linux 内核启动开始系统设置,找到一个init.rc文件启动初始化进程
-
init进程初始化和启动属性服务,之后开启Zygote进程
-
Zygote开始创建JVM并注册JNI方法,开启SystemServer
-
启动Binder线程沲和SystemServiceManager,并启动各种服务
-
AMS启动Launcher
Zygote 进程
Zygote 的中文意思是受精卵,从这个意思里也可以看出 Zygote 进程是用来分裂复制(fork)的,实际上所有的 App 进程都是通过对 Zygote 进程的 Fork 得来的。Zygote 会在其启动后,预加载必要的 Java Classes 和 Resources,并启动 System Server ,并打开 /dev/socket/zygote
socket 去监听启动应用程序的请求
Android进程与Linux进程一样. 默认情况下, 每个apk运行在自己的Linux进程中. 另外, 默认一个进程里面只有一个线程—主线程. 这个主线程中有一个Looper实例, 通过调用Looper.loop()从Message队列里面取出Message来做相应的处理,就是我们常说的Handlder原理
Launcher应用启动
我们从系统源码 packages\apps\Launcher2\src\com\android\launcher2\
目录下可以找到Launcher.java
文件,当我们用手点击一个图标时,就到了这个类执行onClick(View view)
方法,会把这个应用的相关信息传入
获取一个intent
-->startActivitySafely(v, intent, tag)
–>startActivity(v, intent, tag);
–>startActivity(intent);
startActivity(intent)
会开一个APP进程
ActivityThread.java
做为入口
这里是Launcher点击应用图标的入口
这里放个startActivitySafely
方法的源码
下面是大神老师神级画作
下面给出一个好看一点的图
app白屏和黑屏的一般解决方案
- 在自己的
<style name="AppTheme" parent="Theme.AppCompat.Light">
中加入windowsbackground
,这样,在App启动的时候就会直接弹出设置的背景
- 设置
windowbackground
为透明的<item name="android:windowIsTranslucent">true</item>
前面两种方法都有一个问题,就是在所有Activity启动的时候都会先显示这个默认的图片,如果是透明的话会出现点了图标没反映的情况
-
单独制作一个主题
<style name="AppTheme.Launcher"> <item name="android:windowBackground">@drawable/bg</item> </style> <style name="AppTheme.Launcher1"> <item name="android:windowBackground">@drawable/bg</item> </style> <style name="AppTheme.Launcher2"> <item name="android:windowBackground">@drawable/bg</item> </style>
然后在Menifest中相应的Activity下设置
<activity android:theme="@style/AppTheme.Launcher"
然后在程序中使用
setTheme(R.style.AppTheme);
让APP中所有的activity还是使用以前的样式,这样做就只有启动时才使用自己的样式
-
介绍下qq中方式,在style中设置下面的属性
关闭预显示 <item name="android:windowDisablePreview">true</item> 背景设置为空 <item name="android:windowBackground">@null</item>
qq比较牛逼的一点是他在Application中不初始化任何的东西,将启动时间优化到极致,下面会讲到具体的方法
-
其实大多数应用不需要做到像qq那样启动速度快到极致,像腾讯系、阿里系的一些应用都是只显示一张图片,然后开始显示一个3秒左右的广告,在显示广告的时间里进行一些初始化
Trace工具分析代码执行时间
黑白屏的优化只是表面上的优化,只是做到让用户觉得启动速度很快,但实际启动速度一点都没变,下面就该介绍真正的启动优化
工欲善其事,必先利器其器,google小姐已经为我们准备好了工具
Debug.startMethodTracing(filePath);
中间为需要统计执行时间的代码
Debug.stopMethodTracing();
或者直接使用Android Device file Explorer导出的文件
adb pull /storage/emulated/0/app1.trace把文件拉出来分析
把pull到电脑上的文件拖到AS中就可以分析了
查看页面启动时间
sdk版本4.4以前
通过命令
adb shell am start -W com.lqr.wechat/com.lqr.wechat.activity.SplashActivity
可以查看页面的启动时间
ThisTime:最后一个启动的Activity的启动耗时;
TotalTime:自己的所有Activity的启动耗时;
WaitTime: ActivityManagerService启动App的Activity时的总时间(包括当前Activity的onPause()和自己Activity的启动)。
AM.java在系统源码中的路径
frameworks\base\cmds\am\src\com\android\commands\am
APP启动时间优化
优化方案:
1.开线程
内部没有创建handler 没有操作UI的事件 对异步要求不高
2.懒加载
用到的时候再初始化,如网络,数据库操作
引用文章
-
Google工程师多图详解Android系统架构 https://yq.aliyun.com/articles/301672
-
Android启动流程 、app安装和启动原理 https://www.jianshu.com/p/12de32b31836