Android性能優(yōu)化——啟動優(yōu)化

一、前言

APP優(yōu)化是我們進階高級開發(fā)工程師的必經(jīng)之路,而APP啟動速度的優(yōu)化,也是我們開啟APP優(yōu)化的第一步。用戶在使用我們的軟件時,交互最多最頻繁的也就是APP的啟動頁面,如果啟動頁面加載過慢,很可能造成用戶對我們APP的印象過差,進而消耗了用戶的耐心,更嚴重可能導(dǎo)致用戶的卸載行為。這也是微信始終堅持使用“一個小人望著地球”作為啟動頁面的背景,并且堅持不添加啟動廣告的的原因。

二、APP的三種啟動方式

來看一下Google官方文檔《Launch-Time Performance》對應(yīng)用啟動優(yōu)化的概述;

應(yīng)用的啟動可以分為冷啟動,熱啟動和溫啟動,而啟動最慢、耗時最長的就是冷啟動。

冷啟動(cold start)

當(dāng)應(yīng)用啟動時,后臺沒有該應(yīng)用的進程(常見如:進程被殺、首次啟動等),這時系統(tǒng)會重新創(chuàng)建一個新的進程分配給該應(yīng)用。

熱啟動(hot start)

這種啟動會從已有的進程中來啟動應(yīng)用,通俗來講就是已經(jīng)啟用的應(yīng)用,通過back鍵或者home鍵回到系統(tǒng)主界面,再次通過最近任務(wù)重新打開Activity的過程。開銷比冷啟動更小。

暖啟動(warm start)

暖啟動產(chǎn)生的場景很多。常見如:1。用戶使用返回鍵退出應(yīng)用,然后馬上又重新啟動應(yīng)用。2.應(yīng)用被內(nèi)存清除,再次打開應(yīng)用,會通過OnCreate()中保存的實例狀態(tài)恢復(fù)。

冷啟動是從頭開始啟動APP,而其他兩種啟動方式是從后臺活動返回到前臺的一個過程。熱啟動和暖啟動沒有明顯的區(qū)分界限,我們姑且把熱啟動和暖啟動統(tǒng)稱為熱啟動。開發(fā)中我們更多的關(guān)注冷啟動優(yōu)化,本文也是從Android的實例從發(fā),分析冷啟動的啟動過程,并給出冷啟動的優(yōu)化方案。

三、APP的冷啟動過程

冷啟動開始時,系統(tǒng)會依次執(zhí)行三個任務(wù)去啟動APP:

  • 加載和啟動應(yīng)用程序
  • APP啟動后,立即創(chuàng)建一個空白的啟動Window
  • 創(chuàng)建APP的進程

在這三個任務(wù)執(zhí)行后,系統(tǒng)創(chuàng)建了應(yīng)用進程,那么應(yīng)用進程接下來會執(zhí)行下一步:

  • 創(chuàng)建APP對象
  • 開啟一個主線程
  • 創(chuàng)建啟動頁的Activity
  • 加載View
  • 布局view到屏幕
  • 進行初始繪制顯示視圖

當(dāng)應(yīng)用進程完成初始繪制之后,系統(tǒng)進程用啟動頁的Activity來替換當(dāng)前顯示的空白Window,這個時刻用戶就可以使用App了。

四、APP啟動時間

APP的啟動時間是我們可以檢驗優(yōu)化效果的依據(jù),啟動時間是指打開應(yīng)用從初始化到顯示啟動頁Activity的這一段時間。
Google官方的解釋:APP startup time

使用過logcat查看啟動時間

在Android4.4(API level 19)以上的Android版本上,當(dāng)啟動應(yīng)用時Android Studio自動會在logcat中輸出啟動時間。 這個時間從應(yīng)用啟動(創(chuàng)建進程)開始計算,到完成視圖的第一次繪制(即Activity內(nèi)容對用戶可見)為止。

如Display顯示:

I/ActivityManager: Displayed com.example.app/com.example.app.SplashActivity: +1s742ms (total +49s450ms)

reportFullyDrawn()方法

Activity 的reportFullyDrawn()方法,
它會在Logcat里打印從apk初始化到reportFullyDrawn()方法被調(diào)用用了多長時間(文章的reportFullyDrawn()SplashActivity中的onCreate()中執(zhí)行,可以看到顯示的時間和Displayed的是一摸一樣的)

I/ActivityManager: Fully drawn com.example.app/com.example.app.SplashActivity: +1s742ms (total +49s450ms)

執(zhí)行adb命令手動查看啟動時間

adb shell am start -W [packagename]/[packagename.SplashActivity]

輸出:

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.app/.SplashActivity }
Status: ok
Activity: com.example.app/.SplashActivity
ThisTime: 1368
TotalTime: 1368
WaitTime: 1432
Complete

ThisTime:最后一個啟動的Activity的啟動耗時;

TotalTime:自己的所有Activity的啟動耗時;

只用關(guān)注TotalTime就行了

啟動時間標(biāo)準(zhǔn)

官方給出,當(dāng)啟動時間超出以下指標(biāo)時,會被認為啟動時間過長,這是就需要考慮仔細優(yōu)化啟動時間。

  • 冷啟動時間超過5s
  • 熱啟動時間超過1.5s
  • 暖啟動時間超過2s

說了一大堆啟動的基礎(chǔ)知識,下邊開始講解真正的優(yōu)化實戰(zhàn)

五、啟動優(yōu)化實戰(zhàn)

解決應(yīng)用剛啟動時的白屏問題

前邊講到,應(yīng)用初始化會進行一系列進程的創(chuàng)建,資源的初始化工作,這段時間系統(tǒng)會先分配一個空白的Window,這會造成用戶打開應(yīng)用到顯示第一個可交互的Activity,會經(jīng)歷一段白屏的時間。

這時我們可以在給app定義一個主題去解決,在Activity顯示出來之前先顯示一個主題背景,去填補空白的Window階段。

定義一個Splash主題

    <!--Splash launcher-->
    <style name="LauncherTheme" parent="AppTheme">
        <item name="android:windowBackground">@mipmap/ic_splash_bg</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
    </style>

manifest中引用該主題

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

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

最后記得在啟動頁顯示以后恢復(fù)默認的APP主題

  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setTheme(R.style.AppTheme)
        setContentView(R.layout.activity_splash)
      
  }

這種方法只是視覺上給用戶一種快速啟動的感覺,不能減少實際的啟動時間。

避免Application初始化過重

隨著我們工程越做越大,第三方庫和組件也逐漸被依賴到我們的項目中,避免不了會在Application的onCreate()中執(zhí)行很多第三方庫的初始化工作。大量的初始化工作導(dǎo)致該生命周期過于沉重,可能會加長應(yīng)用的啟動時間,因此我們應(yīng)該對這些第三方庫進行分類和優(yōu)化。

  • 必須在onCreate()且是主進程中初始化
  • 可以延遲,但是需要在Application中初始化
  • 可以延遲到啟動頁的生命周期回調(diào)中初始化
  • 延遲到用的時候再初始化

大家可以根據(jù)自身項目去整理代碼,可以延遲執(zhí)行的應(yīng)該放在IntentService或者Work Thread中進行初始化。

  • 例如EventBus 需要在Activiy中使用的,必須在Application中初始化
  • 例如Bugly ,GrowingIO等類似庫的可以放在Work Thread中初始化
  • 例如地圖定位、ImageLoad可以延遲到使用之前初始化
  • SplashActivity中網(wǎng)絡(luò)加載的資源,可以首次加載存放在緩存中,下次啟動的時候再顯示
  • 注意有些第三方庫必須在主線程中初始化
  • 避免耗時操作,如數(shù)據(jù)庫I/O操作不要放在主線程執(zhí)行
  • 刪除無用或重復(fù)的代碼
  • 減少首屏Activity中的網(wǎng)絡(luò)請求密度
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容