Android App 啟動速度優(yōu)化實現(xiàn)演練

本文由玉剛說寫作平臺提供寫作贊助伶椿,版權(quán)歸玉剛說微信公眾號所有
原作者:羅占偉
版權(quán)聲明:未經(jīng)玉剛說許可,不得以任何形式轉(zhuǎn)載

App啟動方式 冷啟動 熱啟動 溫啟動

冷啟動(Cold start)

冷啟動是指APP在手機啟動后第一次運行齿诉,或者APP進程被kill掉后在再次啟動嗦锐。
可見冷啟動的必要條件是該APP進程不存在,這就意味著系統(tǒng)需要創(chuàng)建進程窃爷,APP需要初始化邑蒋。在這三種啟動方式中姓蜂,冷啟動耗時最長,對于冷啟動的優(yōu)化也是最具挑戰(zhàn)的寺董。因此本文重點談論的是對冷啟動相關(guān)的優(yōu)化覆糟。

溫啟動(Warm start)

App進程存在,當時Activity可能因為內(nèi)存不足被回收遮咖。這時候啟動App不需要重新創(chuàng)建進程滩字,但是Activity的onCrate還是需要重新執(zhí)行的。場景類似打開淘寶逛了一圈然后切到微信去聊天去了御吞,過了半小時再次回到淘寶麦箍。這時候淘寶的進程存在,但是Activity可能被回收陶珠,這時候只需要重新加載Activity即可挟裂。

熱啟動(Hot start)

App進程存在,并且Activity對象仍然存在內(nèi)存中沒有被回收揍诽【魅兀可以重復避免對象初始化,布局解析繪制暑脆。
場景就類似你打開微信聊了一會天這時候出去看了下日歷 在打開微信 微信這時候啟動就屬于熱啟動渠啤。

在最近任務給App加鎖和啟動方式有什么關(guān)系

某些廠商為了用戶體驗提供了給APP上鎖的功能,目的就是讓用戶自己做主是上鎖的APP不被殺添吗,啟動的時候不會處于冷啟動方式沥曹,但是加鎖也不是萬能的,Low memory killer在內(nèi)存極度吃緊的情況下也會殺死加鎖APP,在此啟動時也將以冷啟動方式運行。

AI和啟動方式有什么關(guān)系

AI在進程管理方面可謂是大有可為碟联。MIUI10發(fā)布了進程AI喚醒功能妓美,是APP啟動速度遠超友商。這其中的道理簡單說就是學習用戶的使用習慣鲤孵,提前將App進程創(chuàng)建好壶栋,當用戶打開APP時不會出去冷啟動。比如你是微信重度用戶你發(fā)現(xiàn)用了MIUI10就再也見不到微信啟動頁面的那個地球了普监,這就是AI喚醒的功勞委刘。

從點擊APP圖標到主頁顯示出現(xiàn)需要經(jīng)過的步驟

這里我們來討論冷啟動的過程,進程啟動原則上有四種途徑鹰椒,也就是通過其他進程對該APP的四大組件的調(diào)用來實現(xiàn)锡移。

這里我們重點討論用戶點擊桌面后的APP啟動,通過startActivity方式的啟動漆际。
調(diào)用startActivity,該方法經(jīng)過層層調(diào)用,最終會調(diào)用ActivityStackSupervisor.java中的startSpecificActivityLocked,當activity所屬進程還沒啟動的情況下,則需要創(chuàng)建相應的進程.

void startSpecificActivityLocked(...) {
    ProcessRecord app = mService.getProcessRecordLocked(r.processName,
            r.info.applicationInfo.uid, true);
    if (app != null && app.thread != null) {
         ...//進程已創(chuàng)建
        return
    }
    //創(chuàng)建進程
    mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
}

最終進程由 Zygote Fork進程:


進程啟動后系統(tǒng)還有一個工作就是:進程啟動后立即顯示應用程序的空白啟動窗口淆珊。

一旦系統(tǒng)創(chuàng)建應用程序進程,應用程序進程就會負責下一階段奸汇。這些階段是:
1.創(chuàng)建應用程序?qū)ο?br> 2.啟動主線程
3.創(chuàng)建主要Activity
4.繪制視圖(View)
5.布局屏幕
6.執(zhí)行初始化繪制

而一旦App進程完成了第一次繪制施符,系統(tǒng)進程就會用Main Activity替換已經(jīng)展示的Background Window往声,此時用戶就可以使用App了。

image.png

這里很明顯有兩個優(yōu)化點:
Application OnCrate()優(yōu)化
當APP啟動時戳吝,空白的啟動窗口將保留在屏幕上浩销,直到系統(tǒng)首次完成繪制應用程序。此時听哭,系統(tǒng)進程會交換應用程序的啟動窗口慢洋,允許用戶開始與應用程序進行交互。如果應用程序中重載了Application.onCreate()陆盘,系統(tǒng)會調(diào)用onCreate()方法普筹。之后,應用程序會生成主線程(也稱為UI線程)隘马,并通過創(chuàng)建MainActivity來執(zhí)行任務太防。
Activity onCreate()優(yōu)化
onCreate()方法對加載時間的影響最大,因為它以最高的開銷執(zhí)行工作:加載并繪制視圖酸员,以及初始化Activity運行所需的對象蜒车。

啟動速度優(yōu)化

如何對啟動時間進行量化?

1.目前為止見過最最牛逼的是使用機械手和高速相機測試幔嗦,手機開機后使用機械手點擊應用桌面圖標酿愧,高速相機記錄啟動過程,后續(xù)通過程序分析視頻崭添,從機械手點擊圖標到Activity顯示出來使用了多少時間寓娩。這種方式是最直觀和精確的叛氨,但是成本也很高呼渣。

2.通過shell 命令

adb shell am start -W [packageName]/[packageName.MainActivity]

執(zhí)行成功后將返回三個測量到的時間:
ThisTime:一般和TotalTime時間一樣午衰,除非在應用啟動時開了一個透明的Activity預先處理一些事再顯示出主Activity硝训,這樣將比TotalTime小均抽。
TotalTime:應用的啟動時間裸违,包括創(chuàng)建進程+Application初始化+Activity初始化到界面顯示艾君。
WaitTime:一般比TotalTime大點蓝丙,包括系統(tǒng)影響的耗時径簿。

3.可以通過在代碼中增加log來計算啟動時間
4.使用systrace

Application OnCrate()優(yōu)化

1.第三方SDK初始化的處理
Application是程序的主入口哭懈,很多三方SDK示例程序中都要求自己在Application OnCreate時做初始化操作饭冬。這就是增加Application OnCreate時間的主要元兇使鹅,所以需要盡量避免在Application onCreate時同步做初始化操作。比較好的解決方案就是對三方SDK就行懶加載昌抠,不在Application OnCreate()時初始化患朱,在真正用到的時候再去加載。
下面實例對比下ImageLoader在采用懶加載后啟動速度優(yōu)化炊苫。

一般我們在使用imageLoader時都會在Application onCreate()時在主線程加載:

public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        ImageLoaderConfiguration.Builder config =
                new ImageLoaderConfiguration.Builder(this);
        ImageLoader.getInstance().init(config.build());
    }
}

此時使用adb shell am start -W [packageName]/[packageName.MainActivity]檢測應用啟動時間裁厅,每次執(zhí)行命令時需要殺死進程冰沙。

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.luozhanwei.myapplication/.MainActivity }
Status: ok
Activity: com.luozhanwei.myapplication/.MainActivity
ThisTime: 423
TotalTime: 423
WaitTime: 441

Total time在423ms之間,下面是封裝了一個懶加載ImageLoader的工具類示例:

public class ImageUtil {

    private static boolean sInit;

    private synchronized static void ensureInit() {
        if (sInit) {
            return;
        }
        ImageLoaderConfiguration.Builder config =
                new ImageLoaderConfiguration.Builder(SecurityCoreApplication.getInstance());
      ....
        // Initialize ImageLoader with configuration.
        ImageLoader.getInstance().init(config.build());
        sInit = true;
    }

public static void display(String uri, ImageView imageView, boolean cacheOnDisk) {
        imageView.setImageResource(R.drawable.icon_app_default);
        ensureInit();
        ImageLoader loader = ImageLoader.getInstance();
        if (cacheOnDisk) {
            loader.displayImage(uri, imageView);
        } else {
            loader.displayImage(uri, imageView, OPTIONS_NO_CACHE_DISK);
        }
    }

使用這種方案后的啟動時間:

Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.luozhanwei.myapplication/.MainActivity }
Status: ok
Activity: com.luozhanwei.myapplication/.MainActivity
ThisTime: 389
TotalTime: 389
WaitTime: 405

看到TotalTime比之前減少了34ms(給出的數(shù)據(jù)為10次檢測平均值)执虹。

所以Application OnCreate 避免在主線程做大量耗時操作拓挥,例如和IO相關(guān)的邏輯,這樣都會影響到應用啟動速度袋励。如果必須要做需要放到子線程中侥啤。

Activity onCreate()優(yōu)化

減少LaunchActivity的View層級,減少View測量繪制時間插龄。
避免主線程做耗時操作

用戶體驗優(yōu)化

消除啟動時的白屏/黑屏


冷啟動白屏.gif

為什么啟動時會出現(xiàn)短暫黑屏或白屏的現(xiàn)象愿棋?當用戶點擊你的app那一刻到系統(tǒng)調(diào)用Activity.onCreate()之間的這個時間段內(nèi),WindowManager會先加載app主題樣式中的windowBackground做為app的預覽元素均牢,然后再真正去加載activity的layout布局糠雨。
很顯然,如果你的application或activity啟動的過程太慢徘跪,導致系統(tǒng)的BackgroundWindow沒有及時被替換甘邀,就會出現(xiàn)啟動時白屏或黑屏的情況(取決于你的主題是Dark還是Light)。


解決方案
1.甩鍋給系統(tǒng)
使用透明主題 <item name="android:windowIsTranslucent">true</item>
Activity.onCreate()之前App不做顯示垮庐,這樣用戶誤以為是手機慢了松邪,這種瞞天過海的方案大家還是不要用了。

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>

</resources>

效果如下:


甩鍋 .gif

2.主題替換
我們在style中自定義一個樣式Lancher哨查,在其中放一張背景圖片逗抑,或是廣告圖片之類的

<style name="AppTheme.Launcher">
        <item name="android:windowBackground">@drawable/bg</item>
    </style>

把這個樣式設置給啟動的Activity

<activity
            android:name=".activity.SplashActivity"
            android:screenOrientation="portrait"
            android:theme="@style/AppTheme.Launcher"
            >

然后在Activity的onCreate方法,把Activity設置回原來的主題

@Override
    protected void onCreate(Bundle savedInstanceState) {
        //替換為原來的主題寒亥,在onCreate之前調(diào)用
        setTheme(R.style.AppTheme);
        super.onCreate(savedInstanceState);
    }

這樣在啟動時就通過給用戶看一張圖片或是廣告來防止黑白屏的尷尬邮府。


增加啟動頁面.gif

這里我們修改的windowBackground實際上是statringWindow:
https://androidperformance.com/2018/05/20/zhihu-startingwindow/
http://gityuan.com/2017/01/15/wms_starting_window/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市溉奕,隨后出現(xiàn)的幾起案子褂傀,更是在濱河造成了極大的恐慌,老刑警劉巖加勤,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仙辟,死亡現(xiàn)場離奇詭異,居然都是意外死亡鳄梅,警方通過查閱死者的電腦和手機叠国,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來戴尸,“玉大人粟焊,你說我怎么就攤上這事。” “怎么了吆玖?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵筒溃,是天一觀的道長。 經(jīng)常有香客問我沾乘,道長怜奖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任翅阵,我火速辦了婚禮歪玲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘掷匠。我一直安慰自己滥崩,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布讹语。 她就那樣靜靜地躺著钙皮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪顽决。 梳的紋絲不亂的頭發(fā)上短条,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音才菠,去河邊找鬼。 笑死,一個胖子當著我的面吹牛渠牲,可吹牛的內(nèi)容都是我干的贤徒。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼潘明!你這毒婦竟也來了钳降?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤礁击,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后更耻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體号涯,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡域蜗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年霉祸,在試婚紗的時候發(fā)現(xiàn)自己被綠了筑累。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡丝蹭,死狀恐怖慢宗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤镜沽,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布敏晤,位于F島的核電站,受9級特大地震影響缅茉,放射性物質(zhì)發(fā)生泄漏茵典。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一宾舅、第九天 我趴在偏房一處隱蔽的房頂上張望统阿。 院中可真熱鬧,春花似錦筹我、人聲如沸扶平。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽结澄。三九已至,卻和暖如春岸夯,著一層夾襖步出監(jiān)牢的瞬間麻献,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工猜扮, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留勉吻,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓旅赢,卻偏偏與公主長得像齿桃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子煮盼,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344