Android 你應該知道的的應用冷啟動過程分析和優化方案

你有沒有發現,點擊安卓手機桌面上的App圖標時,有時候應用馬上進入主界面,有時候要經歷好幾秒甚至更久的白屏(也可能是黑屏)時間才能進入主界面呢?這其實是安卓應用常見的冷熱啟動問題。本文就和大家一起聊聊冷熱啟動方式和啟動頁的體驗優化方案。

啟動方式

安卓應用的啟動方式分為三種:冷啟動、暖啟動、熱啟動,不同的啟動方式決定了應用UI對用戶可見所需要花費的時間長短。顧名思義,冷啟動消耗的時間最長。基于冷啟動方式的優化工作也是最考驗產品用戶體驗的地方。談及優化之前,我們先看看這三種啟動方式的應用場景,以及啟動過程中系統都做了些什么工作。

冷啟動 (Cold start)

在安卓系統中,系統為每個運行的應用至少分配一個進程 (多進程應用申請多個進程) 。從進程角度上講,冷啟動就是在啟動應用前,系統中沒有該應用的人和進程信息 (包括 Activity、Service 等) 。所以,冷啟動產生的場景就很容易理解了,比如設備開機后應用的第一次啟動,系統殺掉應用進程 (如:系統內存吃緊引發的 kill 和 用戶主動產生的 kill) 后 的再次啟動等。那么自然這種方式下,應用的啟動時間最長,因為相比另外兩種啟動方式,系統和我們的應用要做的工作最多。

應用發生冷啟動時,系統有三件任務要做:

  1. 開始加載并啟動應用;

  2. 應用啟動后,顯示一個空白的啟動窗口;

  3. 創建應用進程信息;

系統創建應用進程后,應用就要做下面這些事情:

  1. 初始化應用中的對象 (比如 Application 中的工作);

  2. 啟動主線程 (UI 線程) ;

  3. 創建第一個 Activity;

  4. 加載內容視圖 (Inflating) ;

  5. 計算視圖在屏幕上的位置排版 (Laying out);

  6. 繪制視圖 (draw)。

只有當應用完成第一次繪制,系統當前展示的空白背景才會消失,才會被 Activity 的內容視圖替換掉。也就是這個時候,用戶才能和我們的應用開始交互。下圖展示了冷啟動過程系統和應用的一個工作時間流:

這其中有兩個 creation 工作,分別為 Application 和 Activity creation。從圖中看出,他們均在 View 繪制展示之前。所以,在應用自定義的 Application 類和 第一個 Activity 類中,onCreate() 方法做的事情越多,冷啟動消耗的時間越長。

暖啟動 (Warm start)

當應用中的 Activities 被銷毀,但在內存中常駐時,應用的啟動方式就會變為暖啟動。相比冷啟動,暖啟動過程減少了對象初始化、布局加載等工作,啟動時間更短。但啟動時,系統依然會展示一個空白背景,直到第一個 Activity 的內容呈現為止。

熱啟動 (Lukewarm start)

相比暖啟動,熱啟動時應用做的工作更少,啟動時間更短。熱啟動產生的場景很多,常見如:用戶使用返回鍵退出應用,然后馬上又重新啟動應用。

啟動時間

從 Android 4.4 (API 19) 開始,Logcat 自動幫我們打印出應用的啟動時間。這個時間值從應用啟動 (創建進程) 開始計算,到完成視圖的第一次繪制 (即 Activity 內容對用戶可見) 為止。如:

11-15 14:06:25.710 1071-1130/? I/ActivityManager: Displayed com.yifeng.qqtemp/.MainActivity: +3s610ms

對應在 logcat 窗口上的顯示如圖 (記得修改過濾條件) :

對于用戶來講,看不到具體的啟動時間,而是應用啟動時白屏展示的體驗問題。舉個例子來對比一下冷熱啟動的實際啟動情況。新建一個工程,為了更好地模擬演示冷熱啟動效果,這里我在自定義 Application 類的 onCreate 方法中添加了如下代碼來延長應用的冷啟動時間:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

然后第一次編譯運行,應用采取冷啟動的方式打開 (使用菜單鍵關閉最近打開的應用,也能達到促使應用使用冷啟動方式,延長啟動時間的效果) ;接著使用返回鍵退出應用,再點擊桌面應用圖標,應用將采用熱啟動的方式打開。整個操作流程對應的效果如圖:

可以看到,冷啟動方式下,應用要經歷一個短暫的白屏時間 (這個時間的長短視具體情況而定),用戶體驗極其不好。相比而言,熱啟動方式下,用戶可以較快進入 Activity 主界面與應用發生交互行為。

優化方案

應用的冷啟動總是無法避免的,也就是說冷啟動時用戶總要經歷一個啟動等待時間。開發人員唯一能做的就是在 Application 和 第一個 Activity 中,減少 onCreate() 方法的工作量,從而縮短冷啟動的時間。像應用中嵌入的一些第三方 SDK,都建議在 Application 中做一些初始化工作,開發人員不妨采取懶加載的形式移除這部分代碼,而在真正需要用到第三方 SDK 時再進行初始化。

還有一種簡單粗暴的方式就是通過主題設置,不顯示啟動時的白屏背景。新建一個主題樣式,并添加如下屬性:

<style name="LaunchStyle" parent="AppTheme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowNoTitle">true</item>
</style>

<item name="android:windowDisablePreview">true</item>

然后將這個主題樣式設置給第一個啟動的 Activity ,如:

<activity 
    android:name=".MainActivity"
    android:theme="@style/LaunchStyle">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

備注:這里沒有將該主題設置在 Application 標簽里,主要是該主題只適用于第一個 Activity,如果放置在 Application 標簽中會修改所有 Activity 的主題樣式。

再修改該 Activity 類的代碼,在加載布局視圖前,將主題修改回來:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setTheme(R.style.AppTheme);

    setContentView(R.layout.activity_main);
}

這么設置之后,效果如圖:

可以看到,冷啟動方式下,用戶點擊桌面圖標,沒有任何反應,過一段時間應用才打開。其實這里只是將白屏背景透明化或者隱藏起來而已。

很顯然,這種處理方式用戶體驗也極差。不過可喜的是,我們可以通過主題中的 windowBackground 屬性,自定義應用啟動時的窗口背景。至于這個背景如何設計,Google 已經在官網上給了建議和規范,可以參考: Launch screens 。其實就是兩種樣式,如圖:

左圖采用應用的 Logo 和 Slogan (甚至為了簡單,Slogan 都可以不要),可以增強品牌推廣效應;右圖利用了 placeholder ,與主界面的 UI 框架保持一致,給用戶產生一種應用啟動非常快的視覺感受。這兩種方案各自目的和應用場景有所不同,但設計理念確實不錯。下面我們一一模仿實現,先看第一種。

新建一個名為 shape_launch.xml 的 drawable 文件,內容如下:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:opacity="opaque">

    <item android:drawable="@color/colorPrimary"/>
    <item >
        <bitmap
            android:src="@mipmap/ic_launcher"
            android:gravity="center" />
    </item>

</layer-list>

然后修改 styles.xml 文件中的主題樣式:

<style name="LaunchStyle" parent="AppTheme">
    <item name="android:windowBackground">@drawable/shape_launch</item>
</style>

最后將這個主題設置給啟動的 Activity,設置過程和上面隱藏啟動窗口時的設置一樣。效果如圖:

第二種,使用與主界面 UI 框架一致的 placeholder 內容,這種情況下需要計算諸如 Statusbar、Toolbar 控件的高度,shape_launch.xml 內容如下:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:opacity="opaque">

    <item android:drawable="@color/colorPrimaryDark"/>
    <item
        android:drawable="@color/colorPrimary"
        android:top="25dp"/>
    <item
        android:top="81dp"
        android:drawable="@android:color/white">
    </item>

</layer-list>

這里模擬了一個高度為25dp的狀態欄和一個高度為56dp的標題欄,給用戶一種錯覺:點擊桌面圖標,應用立即啟動并進入主界面。效果如圖:

以上兩種方式是按照 Google 的建議實現的 UI 效果,當然你還可以有更好的設計方式,只要能夠解決冷啟動帶來的白屏過渡問題,都能帶來不錯的用戶體驗。比如你還可以適度結合 Activity 內容視圖使用動畫過渡效果,比如:

或者這樣

 

來自:http://yifeng.studio/2016/11/15/android-optimize-for-cold-start/

 

 本文由用戶 parissportifs31 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!