这是普通app第一次启动时的过程图:
可以看出:
app在第一次启动时,有很明显的白屏现象;
在点击退出键退出程序后,再次启动,则不再有白屏现象;
当手动杀死进程后,再次启动app,白屏现象复现。
原因分析:
Android在第一次启动时,会先启动application,再启动activity,故会有一段启动application导致的白屏时间,此时并没有任何页面(activity)被启动;
而点击退出后,Android实际上只finish掉了activity,应用以一种低优先级进程的方式存在内存中,此时基本不占用cpu和消耗电量,但是占用一定量的内存。当内存不足时,该类进程会被优先杀死。但正是由于有该类进程的存在,使得我们再次启动app时,由于application已经初始化完毕,该app可以实现快速的启动,这也正是android的优势所在(想起360手机动不动就杀掉后台进程的行为…只能呵呵…),所以再次启动app时,没有白屏现象发生。
但是为什么公司的其中一个app每次启动都白屏呢?
研究代码发现,该app的退出在调用了所有activity的finish之后,直接调用了System.exit(0) ; 简化代码如下:
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
&& event.getAction() == KeyEvent.ACTION_UP) {
System.exit(0);
}
return super.dispatchKeyEvent(event);
}
原因就在于 :
finish只是关闭Android的一个类–activity。而System.exit(0)则是杀死进程。进程都被杀死,application必然不复存在,再次启动也必然白屏。这也是为什么除非特殊情况,否则不推荐直接System.exit(0)的方式退出程序,这相当于把android的快速启动优势直接抹杀掉了啊…
还有个疑问:
System.exit(0); 会把Service杀掉吗?
于是开始新一轮测试,下面的service代码:
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
Log.e("TestExit", "Test");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
1.运行在主线程中的service,然后System.exit(0)退出程序。不出意外service会被杀掉。
测试结果:确实被杀掉了
2.给service指定一个process,使其运行在另一个进程中。然后System.exit(0)退出程序。
测试结果:System.exit(0) 不会杀掉该service
测试结论:service非bind模式下,是否存活与进程和自身相关。
而System.exit(0)只杀死当前进程。
3.通过下图方式杀死进程:
测试结果:主线程和该Service都被杀死了
测试结论:测试2说明service的存活与进程有关,现在service被杀死了,说明service所在的新进程也被杀死了。那么为什么呢?
打开设置-应用程序管理-app,如下图:
原来如此,在上滑关闭app就等同于在此图中点击停止运行,这个操作会关闭与app所有相关的进程或服务。
综上:停止运行(关闭app所有相关)>System.exit(0)(关闭当前进程)>finish(关闭activity)
白屏的解决办法
无论是首次启动白屏,还是由于程序中使用System.exit(0)退出导致的次次启动白屏,对于程序而言都是很不美观的。如何解决呢?
只需要给Application添加一个带背景的theme(可以是app Logo,也可以是启动页图片,可以实现无缝过渡),就可以解决这种白屏突兀的现象。
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".LaunchActivity"
android:theme="@style/StartBackGroundTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
theme内容写在res-values-styles下:
NoTitle和Fullscreen根据需要可以自行删去,个人觉得启动页这样写比较美观,并且很多app也是这样做的。同时这两个属性也是Theme要写在启动页Activity里的原因,这样只有启动页会全屏无状态栏的显示…
<style name="StartBackGroundTheme" parent="AppTheme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowBackground">@drawable/start_background</item>
</style>
关于Android的各种进程,会在下次进行学习讨论