Android應用冷啟動解析和優化方案
前言
在我們點選Android手機桌面APP圖示時,有時候我麼會發現,應用並不是直接進入閃屏頁或者應用主頁面,而是會有一個短暫時間的白屏才能進去。但如果我們點選Back鍵退出應用,在點選返回的時候卻沒有白屏或者白屏時間幾乎不可見。為什麼會出現這種情況呢?這就涉及到Android應用冷熱啟動的問題。
啟動方式
Android應用的啟動方式可以分為三種:冷啟動,暖啟動,熱啟動;不同的啟動方式表示著應用載入的方式不同,相對應的就產生了應用UI呈現給使用者所需要花費的時間不同。
啟動時間
Android 4.4(API 19)開始,Logcat可以自動打印出應用的啟動時間,這個時間值從應用啟動(建立程序)開始計算,到完成是檢視的而第一次繪製(第一個Activity的介面第一次對使用者可見)為止。
Cold Start (冷啟動)
什麼是冷啟動? 比如裝置開機後應用第一次啟動,系統殺死應用程序(包括:使用者主動殺死程序和系統記憶體吃緊引發的Kill)再次啟動等。
在Android系統中,APP啟動時,系統為每個執行的應用至少分配一個程序(多執行緒應用申請多個程序)。從程序角度講,應該冷啟動的時候,是沒有該應用的程序配置資訊的(包括 Application ,四大元件等),這樣冷啟動是所做的工作就會比其他兩種啟動方式多。
冷啟動時,系統主要任務有兩件:
1,開始載入並啟動APP;
2,建立應用程序資訊,進入並顯示第一個Activity UI。
而我們我看到的白屏就是在第二步,配置程序資訊和第一個Activity UI渲染到頁面之前所花費的時間。那麼我們來分析一下系統建立應用程序後,所要處理的事情;
1,初始化應用中的物件(比如Application的建立及其onCreate中的工作)
2,啟動主執行緒;
3,建立第一個Activity;
4,載入佈局檢視(Inflating);
5,初始化控制元件在螢幕上的位置(Laying out)
6,繪製檢視(draw)
只有當應用完成第一次繪製,系統當前展現的空白背景才會被Activity的佈局檢視替換掉。這是使用者才能應用進行互動。在這個流程中主要涉及到Application 的onCreate和第一個Activity的onCreate方法,它們均在View繪製展示之前進行處理。所以在應用自定義的Application類中和第一個Activity類中的onCreate方法處理的邏輯越多,冷啟動花費的時間就越長。
Warm Start (暖啟動)
當APP中的Activities被銷燬,但在記憶體中常駐時,應用的啟動方式就會變為暖啟動。相比於冷啟動,暖啟動過程減少了物件的初始化,佈局載入等工作,啟動時間會縮短。但啟動時,系統忍讓會展現一個空白背景,直到第一個Activity的內容替換。
Lukewarm Start (熱啟動)
熱啟動產生的場景有很多,比如:使用者點選Back鍵退出應用,然後馬上就重新啟動。這是佈局依舊是之前繪製好的,所以花費的時間更少。
優化方案
應用的冷啟動是無法避免的,也就是說冷啟動時使用者總需要經歷一個等待啟動時間。開發人員唯一能做的就是在 Application 和 第一個 Activity 中,減少 onCreate() 方法的工作量,從而縮短冷啟動的時間。像應用中嵌入的一些第三方 SDK,都建議在 Application 中做一些初始化工作,開發人員不妨採取懶載入的形式移除這部分程式碼,而在真正需要用到第三方 SDK 時再進行初始化。
除此之外,還有一種方式就是通過設定應用主題背景的方法,把應用預設展現的白色背景替換被透明背景。我們新建一個主題樣式:
<style name="LaunchStyle" parent="AppTheme">
<!--設定透明背景-->
<!--<item name="android:windowIsTranslucent">true</item>-->
<!--設定無標題-->
<!--<item name="android:windowNoTitle">true</item>-->
</style>
然後在AndroidManifast.xml檔案中將主題設定給第一個啟動的Activity
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true">
<activity
android:name=".MainActivity"
android:theme="@style/MyStyle">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
然後在修改MainActivity的onCreate中,在setContentView(R.layout.avtivity_main)載入佈局之前把主題修改回來
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppTheme);
setContentView(R.layout.activity_main);
}
我們可以看到現在白屏是沒有了,這是應為我們將應用主題背景設定為透明,在我們點選應用圖示之後,其實就已經打開了應用,不過此時應用背景為透明,我們讓看到的是桌面。雖然這樣做白屏是沒有了,但是我們可以明顯看到應用開啟呈現一種卡頓延遲的現象。這種效果相比於白屏更不可取(這是因為我在Aplication的onCreate方法中休眠了三秒)
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
除了上邊這種方法,還有一種更好的解決思路。就是通過android:windowBackground" 設定自定義主題背景,這樣就給到使用者一種很好的視覺過渡效果。可以參考優酷APP效果,直接將原本展示白屏的頁替換成應用的閃屏頁。
<style name="LaunchStyle" parent="AppTheme">
<!--設定Appliction背景-->
<item name="android:windowBackground">@drawable/layout_launch</item>
</style>
<?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/color_white" />
<item>
<bitmap
android:gravity="center"
android:src="@mipmap/baidu" />
</item>
</layer-list>
這是最終的效果,當然如果新增些動畫效果會更好。