天天看點

App冷啟動白屏/黑屏問題分析及解決方案

一、問題背景

最近在做産品首次啟動頁優化功能時,發現在點選啟動launch圖示與切換到子程序頁面時會白屏或黑屏一段時間,時間長短根據不同機型性能不一。

原來看過相關文章,借此機會總結一下app啟動的閃屏頁面是怎麼産生的,該如何優化?

二、問題分析

既然我們想要優化app啟動速度,那我們肯定要了解app啟動的幾種模式:冷啟動(Cold start),熱啟動(Warm start),溫啟動(Lukewarm start)。

隻有冷啟動是從頭開始,其他兩種是将應用從背景切換到前台。是以我們基于冷啟動的情況進行優化。這樣做也可以提高熱啟動與溫啟動的性能。

冷啟動(Cold start):

在冷啟動的時候,系統會開始三個任務:

1. 加載并且啟動app

2. 在啟動後立即顯示一個應用程式的空白視窗(這就是彈出的白屏)

3. 建立app程序

當系統建立應用程式程序,應用程式程序将負責下一階段。這些階段是:

1. 建立app 對象

2. 啟動主線程

3. 建立主activity

4. inflating views

5. Laying out the screen

6. 執行首次繪制

一旦應用程序完成了首次繪制,系統程序就會替換掉目前顯示的背景視窗(白屏/黑屏),将其替換為activity的背景視窗。此時,使用者可以開始使用應用程式。下圖是冷啟動過程流程圖:

App冷啟動白屏/黑屏問題分析及解決方案

熱啟動(Warm start):

與冷啟動相比,熱啟動應用程式要簡單得多,開銷更低。在熱啟動,所有的系統都是把你的activity切換到前台。如果應用程式的activity仍駐留在記憶體中,那麼app不會重複對象初始化,inflating views和重新渲染。

熱啟動顯示與冷啟動場景相同的螢幕行為:先顯示空白螢幕,直到應用程式完成再渲染activity。

溫啟動(Lukewarm start):

使用者退出您的應用,但随後重新啟動它。該過程可能已繼續運作,但應用程式必須通過調用onCreate()從頭開始重新建立activity,這就是典型的溫啟動。

三、問題解決

通過對以上幾種啟動模式的了解,我們知道冷啟動這種模式肯定是最耗時的,也是最需要進行優化的。那麼該如何優化呢?

根據上面對冷啟動的分析可以知道,在系統建立程序之前系統會讀取目前Activity的Theme繪制一個空白窗體,這個空白窗體主要是為了立即給使用者點選回報。

第一種方法(不推薦):

在activity的theme中設定

<item name="android:windowDisablePreview">true</item>
//設定這個屬性可以關閉系統彈出的空白窗體
           

<item name="android:windowIsTranslucent">true</item>
<item name="android:windowNoTitle">true</item>
//将activity theme設定為透明也可以讓使用者不可見空白窗體
           

上面兩種都可以通過取消、透明化系統的空白窗體頁面來達到啟動的“加速”

不過上面兩種設定會造成一個問題:當使用者點選啟動activity後,界面無響應。使用者隻能等待初始化完成,這段時間無法互動,使用者體驗很差,不推薦。

第二種方法(推薦):

既然是讀取Theme,那我們可以在這裡做文章。

我們自定義一個啟動style用來給使用者友好的回報,當activity繪制之前将真正的style還原回去。具體是利用style中的android:windowBackground屬性:

  • 先定義一個drawable,可以使用純色背景,圖檔等。

    Layout XML file:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
            android:opacity="opaque">
    <item android:drawable="@android:color/white"/>
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/launch_logo"/>
    </item>
</layer-list>
           
  • 在style中定義一個launchStyle,設定android:windowBackground為我們剛剛定義的drawable

    style file:

<style name="LaunchStyle" parent="BaseAppTheme">
    <item name="android:windowBackground">@drawable/launch_view</item>
</style>
           
  • 在activity中設定我們的launchStyle。

    Manifest file:

<activity
    android:name=".MyMainActivity"
    ...
    android:theme="@style/LaunchStyle"/>
           

這樣在我們冷啟動我們的app時,看到的不再是空白頁面(白屏/黑屏)而是我們自定義的界面了,展示更友好。

這樣還沒結束還差最後一步也是最重要的一步,在Activity加載真正的界面之前,将Theme設定回正常的Theme。

public class MyMainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    setTheme(R.style.BaseAppTheme);
    super.onCreate(savedInstanceState);
    // ...
  }
}
           

注意: setTheme(R.style.BaseTheme) 一定要在 super.onCreate() 與 setContentView(): 之前調用

三、問題總結

上面通過Theme的解決方法隻是一種互動上的友好提速,我們還是要花費更多的精力在真正的性能調優上:優化布局,避免大量對象初始化,延遲初始化,界面預加載,多線程加載等。

App啟動速度是一個App是否優秀很重要的标志,我們應該不斷的提升,優化。

參考連結:https://developer.android.com/topic/performance/launch-time.html