這是普通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的各種進程,會在下次進行學習討論