Android 啓動退出時的相關問題

最近公司需求需要往兩個app加啓動頁廣告,研究發現,其中一個app在點擊退出鍵退出時再啓動有很明顯的白屏現象,而另一個app則沒有,於是在做了一系列測試後有了下面的博客。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章