App启动方式
如何启动App呢?
说到底就是点击屏幕的App图标。但是点击的时候会发现有时进入App首页很快,有时很慢,有时中间还有个白屏。有时中间还有个黑屏。
造成这样的情况,是什么原因呢?我们先从App启动的方式开始说起。
冷启动
热启动
冷启动
冷启动:当启动应用时,后台没有该应用的进程,这时系统会重新创建一个新的进程分配给该应用。
冷启动的特点:因为系统会重新创建一个新的进程分配给它,所以会创建和初始化Application,在创建和初始化它的Launch Activity(onCreate onMesure onLayout,ondraw),最后展示在界面上
热启动
热启动:当启动应用时,后台存在该应用的进程(back键,home键,应用退出,但是没有销毁),从已有的进程中启动
热启动的特点:从已有的进程中启动,不需要创建和初始化Application ,直接创建和初始化它的Launch Activity
<mark>两者区别:后台进程是否存在相应的进程,创建进程是耗时操作</mark>
应用的启动过程
主要讲解冷启动的情况(分配进程->创建和初始化Application->创建和初始化Launch Activity)
可以参考老罗的Android之旅-Android应用程序启动过程源代码分析
我这里做了下摘要,App启动过程就是:
整个应用程序的启动过程要执行很多步骤,但是整体来看,主要分为以下五个阶段:
一. Step1 - Step 11:
Launcher通过Binder进程间通信机制通知ActivityManagerService,
它要启动一个Activity;
二. Step 12 - Step 16:
ActivityManagerService通过Binder进程间通信机制通知Launcher进入Paused状态;
三. Step 17 - Step 24:
Launcher通过Binder进程间通信机制通知ActivityManagerService,它已经准备就绪进入Paused状态,
于是ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例,
即将要启动的Activity就是在这个ActivityThread实例中运行;
四. Step 25 - Step 27:
ActivityThread通过Binder进程间通信机制将一个ApplicationThread类型的Binder对象传递给ActivityManagerService,
以便以后ActivityManagerService能够通过这个Binder对象和它进行通信;
五. Step 28 - Step 35:
ActivityManagerService通过Binder进程间通信机制通知ActivityThread,
现在一切准备就绪,它可以真正执行Activity的启动操作了。
<mark>有兴趣可以看下源码实现,其实App的启动相当于在Launch 这个应用中点击某个图标进行跳转</mark>
ActivityManagerService就创建一个新的进程,用来启动一个ActivityThread实例
--可以理解成Zygote进程中fork一个新的进程分配给应用.至于Zygote是什么呢?我还没搞懂呢。推荐两篇博客大家自行理解下
Android深入浅出之Zygote
Android系统进程Zygote启动过程的源代码分析
后续理解了,会专门讲解下
如何测量应用启动时间
- 可以通过代码打桩,计算启动时间
- 可以通过秒表计算(肉眼观察,这个很low)
最近查到资料,android是有命令可以计算启动时间的
adb shell am start -W [packageName]/[packageName.launchActivity]
OK,那就拿自己的项目来给大家看看上面两种启动的时间差别
冷启动:
![](http://upload-images.jianshu.io/upload_images/1863168-0b3845cf6a4ef1d1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp)
热启动
![](http://upload-images.jianshu.io/upload_images/1863168-163d2af02ac6a152.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1000/format/webp)
<mark>两者差距时间很多,只能说明在Application做了很多耗时的操作.并且现在大部分的App启动是冷启动,因为用户的习惯就是不喜欢有这么多后台进程,他们喜欢删掉所有进程
提醒:
<mark>避免一些耗时操作在Application中处理,并减少LaunchActivity的View层级,减少View测量绘制时间
App启动为什么会白屏,黑屏
回到刚开始的问题,为什么有时打开App会出现白屏/黑屏情况
先来解释下为什么会出现白屏/黑屏的原因?
是因为已进入到Activity,但是未加载到布局文件,
就先显示来windows窗口的背景。
黑屏/白屏就是显示的windows背景(这个就是theme的设置)
解决方案:
1.为 Theme 设置背景图;
(会给人一种快速加载的感觉)
<style name="Theme.AppStartLoad" parent="android:Theme">
<item name="android:windowBackground">@drawable/ipod_bg</item>
<item name="android:windowNoTitle">true</item>
</style>
2.为 Theme 设置透明属性
(回给人较慢加载出来感觉,因为需要等布局加载完之后一次性展开)
<style name=“Theme.AppStartLoadTranslucent” parent=“android:Theme”>
<item name=“android:windowIsTranslucent”>true</item>
<item name=“android:windowNoTitle”>true</item>
</style>
这里不展开了,可以看下这个Android开发之解决APP启动白屏或者黑屏闪现的问题
优化冷启动时间的小技巧
按照刚才说的为什么出现白屏/黑屏原因的解决方案。
其实可以在给启动的Activity的Theme中背景设置为启动页的图片,然后在等待加载完activtity的布局后,恢复原来的theme
代码举例:
在style.xml文件
<style name="AppTheme.Launcher">
<item name="android:windowBackground">@drawable/appstart_background
</item>
<span class="hljs-comment"><!--<item name="android:windowIsTranslucent">true</item>--></span>
</span><span class="hljs-tag"></<span class="hljs-name">style</span>></span>
在AndroidManifest.xml
<activity android:name=".AppStartActivity"
android:theme="@style/AppTheme.Launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<span class="hljs-tag"><<span class="hljs-name">category</span> <span class="hljs-attr">android:name</span>=<span class="hljs-string">"android.intent.category.LAUNCHER"</span> /></span>
<span class="hljs-tag"></<span class="hljs-name">intent-filter</span>></span>
<span class="hljs-tag"></<span class="hljs-name">activity</span>></span>
AppStartActivity.java
public class AppStartActivity extends AppCompatActivity {
<span class="hljs-meta">@Override</span>
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(@Nullable Bundle savedInstanceState)</span> </span>{
<span class="hljs-keyword">super</span>.onCreate(savedInstanceState);
<span class="hljs-keyword">try</span> {
Thread.sleep(<span class="hljs-number">3000</span>);
} <span class="hljs-keyword">catch</span> (InterruptedException e) {
e.printStackTrace();
}
setContentView(R.layout.activity_appstart);
}
}
上面的@drawable/appstart_background就是启动页的默认背景。亲测,可用