Android 你應該知道的的應用冷啟動過程分析和優化方案
你有沒有發現,點擊安卓手機桌面上的App圖標時,有時候應用馬上進入主界面,有時候要經歷好幾秒甚至更久的白屏(也可能是黑屏)時間才能進入主界面呢?這其實是安卓應用常見的冷熱啟動問題。本文就和大家一起聊聊冷熱啟動方式和啟動頁的體驗優化方案。
啟動方式
安卓應用的啟動方式分為三種:冷啟動、暖啟動、熱啟動,不同的啟動方式決定了應用UI對用戶可見所需要花費的時間長短。顧名思義,冷啟動消耗的時間最長。基于冷啟動方式的優化工作也是最考驗產品用戶體驗的地方。談及優化之前,我們先看看這三種啟動方式的應用場景,以及啟動過程中系統都做了些什么工作。
冷啟動 (Cold start)
在安卓系統中,系統為每個運行的應用至少分配一個進程 (多進程應用申請多個進程) 。從進程角度上講,冷啟動就是在啟動應用前,系統中沒有該應用的人和進程信息 (包括 Activity、Service 等) 。所以,冷啟動產生的場景就很容易理解了,比如設備開機后應用的第一次啟動,系統殺掉應用進程 (如:系統內存吃緊引發的 kill 和 用戶主動產生的 kill) 后 的再次啟動等。那么自然這種方式下,應用的啟動時間最長,因為相比另外兩種啟動方式,系統和我們的應用要做的工作最多。
應用發生冷啟動時,系統有三件任務要做:
-
開始加載并啟動應用;
-
應用啟動后,顯示一個空白的啟動窗口;
-
創建應用進程信息;
系統創建應用進程后,應用就要做下面這些事情:
-
初始化應用中的對象 (比如 Application 中的工作);
-
啟動主線程 (UI 線程) ;
-
創建第一個 Activity;
-
加載內容視圖 (Inflating) ;
-
計算視圖在屏幕上的位置排版 (Laying out);
-
繪制視圖 (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/