App啟動(dòng)速度優(yōu)化

谷歌官方文檔:https://developer.android.com/topic/performance/launch-time.html#common


一晃财、app啟動(dòng)方式

啟動(dòng)方式分為兩種:冷啟動(dòng)摆昧、熱啟動(dòng)攻冷、溫啟動(dòng)。

1. 冷啟動(dòng)

啟動(dòng)app時(shí)帮哈,后臺(tái)沒有app的進(jìn)程十办,或者進(jìn)程被killed,這叫冷啟動(dòng)累舷。冷啟動(dòng)因?yàn)橄到y(tǒng)會(huì)重新創(chuàng)建一個(gè)新的進(jìn)程分配給它,所以會(huì)先創(chuàng)建和初始化Application類夹孔,再創(chuàng)建和初始化MainActivity類(包括一系列的測(cè)量、布局析孽、繪制)搭伤,最后顯示在界面上。

2. 熱啟動(dòng)

啟動(dòng)app時(shí)袜瞬,后臺(tái)已有app的進(jìn)程(例:按back鍵怜俐、home鍵,應(yīng)用雖然會(huì)退出邓尤,但是該應(yīng)用的進(jìn)程是依然會(huì)保留在后臺(tái)拍鲤,可進(jìn)入任務(wù)列表查看),所以在已有進(jìn)程的情況下汞扎,這種啟動(dòng)會(huì)從已有的進(jìn)程中來啟動(dòng)應(yīng)用季稳,這個(gè)方式叫熱啟動(dòng)。
熱啟動(dòng)因?yàn)闀?huì)從已有的進(jìn)程中來啟動(dòng)澈魄,所以熱啟動(dòng)就不會(huì)走Application這步了景鼠,而是直接走M(jìn)ainActivity(包括一系列的測(cè)量、布局痹扇、繪制)铛漓,所以熱啟動(dòng)的過程只需要?jiǎng)?chuàng)建和初始化一個(gè)MainActivity就行了,而不必創(chuàng)建和初始化Application鲫构,因?yàn)橐粋€(gè)應(yīng)用從新進(jìn)程的創(chuàng)建到進(jìn)程的銷毀浓恶,Application只會(huì)初始化一次。

3. 溫啟動(dòng)

介于冷啟動(dòng)和熱啟動(dòng)之間, 一般來說在以下兩種情況下發(fā)生:
用戶back退出了App, 然后又啟動(dòng). App進(jìn)程可能還在運(yùn)行, 但是activity需要重建结笨。用戶退出App后, 系統(tǒng)可能由于內(nèi)存原因?qū)pp殺死, 進(jìn)程和activity都需要重啟, 但是可以在onCreate中將被動(dòng)殺死鎖保存的狀態(tài)(saved instance state)恢復(fù)包晰。

通過三種啟動(dòng)狀態(tài)的相關(guān)描述, 可以看出我們要做的啟動(dòng)優(yōu)化其實(shí)就是針對(duì)冷啟動(dòng). 熱啟動(dòng)和溫啟動(dòng)都相對(duì)較快.


二湿镀、app啟動(dòng)流程

這里是冷啟動(dòng)流程。在安卓系統(tǒng)上杜窄,應(yīng)用在沒有進(jìn)程的情況下肠骆,應(yīng)用的啟動(dòng)都是這樣一個(gè)流程:當(dāng)點(diǎn)擊app的啟動(dòng)圖標(biāo)時(shí),安卓系統(tǒng)會(huì)從Zygote進(jìn)程中fork創(chuàng)建出一個(gè)新的進(jìn)程分配給該應(yīng)用塞耕,之后會(huì)依次創(chuàng)建和初始化Application類蚀腿、創(chuàng)建MainActivity類、加載主題樣式Theme中的windowBackground等屬性設(shè)置給MainActivity以及配置Activity層級(jí)上的一些屬性扫外、再inflate布局莉钙、當(dāng)onCreate/onStart/onResume方法都走完了后最后才進(jìn)行contentView的measure/layout/draw顯示在界面上,所以直到這里筛谚,應(yīng)用的第一次啟動(dòng)才算完成磁玉,這時(shí)候我們看到的界面也就是所說的第一幀。

00=>start: Application的構(gòu)造器方法
01=>operation: attachBaseContext() 
02=>operation: onCreate方法
03=>operation: Activity 的構(gòu)造方法
04=>operation: onCreate()
05=>operation: 配置主題背景等屬性
06=>operation: onStart()
07=>operation: onResume()
08=>end: 測(cè)量布局繪制顯示在界面上

00->01->02->03->04->05->06->07->08->09

三驾讲、測(cè)量app啟動(dòng)時(shí)間

應(yīng)用的啟動(dòng)時(shí)間:點(diǎn)擊應(yīng)用icon開始創(chuàng)建出一個(gè)新的進(jìn)程直到看到了界面上的第一幀蚊伞,這段時(shí)間就是應(yīng)用的啟動(dòng)時(shí)間。

1.方式一:通過adb shell命令的方式進(jìn)行測(cè)量吮铭,這種方法測(cè)量的最為精準(zhǔn)
$ adb shell am start -W [packageName]/[packageName.LaunchActivity]

執(zhí)行成功后返回三個(gè)測(cè)量得到的時(shí)間:

  1. **ThisTime : **一般和TotalTime時(shí)間一樣时迫,除非在應(yīng)用啟動(dòng)時(shí)開了一個(gè)透明的Activity預(yù)先處理一些事再顯示出主Activity,這樣將比TotalTime小谓晌。
  2. **TotalTime : **應(yīng)用的啟動(dòng)時(shí)間掠拳,包括創(chuàng)建進(jìn)程+Application初始化+Activity初始化到界面顯示。
  3. **WaitTime : **一般比TotalTime大點(diǎn)纸肉,包括系統(tǒng)影響的耗時(shí)溺欧。
    舉個(gè)栗子,下面是對(duì)全視頻的啟動(dòng)時(shí)間測(cè)量:

冷啟動(dòng)時(shí)間:

C:\Users\luguoqiang>adb shell am start -W com.qsp.launcher/com.qsp.launcher.Spla
shActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.L
AUNCHER] cmp=com.qsp.launcher/.SplashActivity }
Status: ok
Activity: com.qsp.launcher/.SplashActivity
ThisTime: 957
TotalTime: 957
WaitTime: 977
Complete

熱啟動(dòng)時(shí)間:

C:\Users\luguoqiang>adb shell am start -W com.qsp.launcher/com.qsp.launcher.Spla
shActivity
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.L
AUNCHER] cmp=com.qsp.launcher/.SplashActivity }
Status: ok
Activity: com.qsp.launcher/.SplashActivity
ThisTime: 284
TotalTime: 284
WaitTime: 312
Complete
2. 方式二:利用Traceview性能分析工具

生成trace文件
Traceview是一個(gè)性能分析工具, 主要是分析當(dāng)前線程情況, 各個(gè)方法執(zhí)行時(shí)間等柏肪,Android studio內(nèi)置的工具姐刁。
ApplicationonCreate開始和結(jié)尾打上trace

Debug.startMethodTracing("App");
...
Debug.stopMethodTracing();

運(yùn)行程序,會(huì)在設(shè)備的sd卡上生成一個(gè)App.trace文件预吆,注意不要忘記加權(quán)限龙填。

DDMS中進(jìn)行分析

1478350802035.png

在下方的方法區(qū)點(diǎn)擊"Real Time/Call", 按照方法每次調(diào)用耗時(shí)降序排.
耗時(shí)超過500ms都是值得注意的。

3. 方式三:Time to initial display

從 4.4 (API 19) 開始拐叉,logcat會(huì)輸出帶有 Diaplay 的 log 岩遗。該值代表從app啟動(dòng)進(jìn)程到完成Activity第一次繪制的時(shí)候完成了下一個(gè)劉流程:
舉個(gè)栗子,全視頻的啟動(dòng)時(shí)間的如下

1478489524776.png
4.方式四:NimbleDroidAndroid 應(yīng)用性能分析服務(wù)

四凤瘦、怎樣優(yōu)化

ApplicationonCreate()中加入了許多耗時(shí)的操作宿礁,把這些初始化的操作放在一個(gè)單獨(dú)的線程中處理。

1. 利用InitializeServiceIntentService來做初始化工作

//TODO IntentService不同于Service蔬芥,具體不同需要搜索資料

[InitializeService.java]
public class InitializeService extends IntentService {

    private static final String ACTION_INIT_WHEN_APP_CREATE = "com.demo.service.action.INIT";

    public InitializeService() {
        super("InitializeService");
    }

    public static void start(Context context) {
        Intent intent = new Intent(context, InitializeService.class);
        intent.setAction(ACTION_INIT_WHEN_APP_CREATE);
        context.startService(intent);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_INIT_WHEN_APP_CREATE.equals(action)) {
                performInit();
            }
        }
    }

    private void performInit() {
        AppLog.d("performInit begin:" + System.currentTimeMillis());
        // 這里進(jìn)行一些耗時(shí)性的初始化,需要注意某些初始化的操作不能在子線程中執(zhí)行梆靖。
        ...
        // init crash helper
        CrashHelper.init(this.getApplicationContext());
        // init Push
        PushPlatform.init(this.getApplicationContext());
        ...
        AppLog.d("performInit end:" + System.currentTimeMillis());
    }
}

Application中的onCreate()處用法如下

public class MyApplication extends MultiDexApplication {

    @Override
    public void onCreate() {
        super.onCreate();
        ...
        InitializeService.start(this);
    }
}

五控汉、啟動(dòng)頁開啟前的白屏or黑屏優(yōu)化

初始化首屏的Activity過程中(或者說在等待第一幀顯示的時(shí)間里)屏幕會(huì)顯示一個(gè)空白/黑色的窗口(顏色基于主題),直至首屏Activity完全啟動(dòng)返吻。
這個(gè)空白的窗口跟主題相關(guān)姑子,所以可以從首屏的主題入手。
給Splash界面加上一個(gè)主題测僵,這個(gè)主題會(huì)在現(xiàn)實(shí)第一幀前提前顯示在界面上街佑,設(shè)置想要展示的背景。
做一個(gè)splash背景

[logo_splash.xml]
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 底層白色 -->
    <item android:drawable="@color/white" />

    <!-- 頂層Logo居中 -->
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/ic_github" />
    </item>
</layer-list>

自定義splashTheme主題

[styte.xml]
<style name="SplashTheme" parent="AppTheme">
    <item name="android:windowBackground">@drawable/logo_splash</item>
</style>

將一個(gè)什么不渲染的布局的Activity作為啟動(dòng)頁

public class LogoSplashActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 注意, 這里并沒有setContentView, 單純只是用來跳轉(zhuǎn)到相應(yīng)的Activity.
        // 目的是減少首屏渲染

        if (AppPref.isFirstRunning(this)) {
            IntroduceActivity.launch(this);
        }
        else {
            MainActivity.launch(this);
        }
        finish();
    }
}

AndroidMainfest.xml設(shè)置為啟動(dòng)屏捍靠,并加上主題

<activity
  android:name=".ui.module.main.LogoSplashActivity"
  android:screenOrientation="portrait"
  android:theme="@style/SplashTheme">
  <intent-filter>
      <action android:name="android.intent.action.MAIN"/>
      <category android:name="android.intent.category.LAUNCHER"/>
  </intent-filter>
</activity>

參考博客:
(TraceView 性能分析工具)[http://mouxuejie.com/blog/2016-02-25/android-tools-traceview/]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末沐旨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子榨婆,更是在濱河造成了極大的恐慌磁携,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件良风,死亡現(xiàn)場(chǎng)離奇詭異谊迄,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)烟央,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門鳞上,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吊档,你說我怎么就攤上這事⊥倥矗” “怎么了怠硼?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長移怯。 經(jīng)常有香客問我香璃,道長,這世上最難降的妖魔是什么舟误? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任葡秒,我火速辦了婚禮,結(jié)果婚禮上嵌溢,老公的妹妹穿的比我還像新娘眯牧。我一直安慰自己,他們只是感情好赖草,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布学少。 她就那樣靜靜地躺著,像睡著了一般秧骑。 火紅的嫁衣襯著肌膚如雪版确。 梳的紋絲不亂的頭發(fā)上扣囊,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音绒疗,去河邊找鬼侵歇。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吓蘑,可吹牛的內(nèi)容都是我干的惕虑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼士修,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼枷遂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棋嘲,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤酒唉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后沸移,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痪伦,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年雹锣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了网沾。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蕊爵,死狀恐怖辉哥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情攒射,我是刑警寧澤醋旦,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站会放,受9級(jí)特大地震影響饲齐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜咧最,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一捂人、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧矢沿,春花似錦滥搭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至摄狱,卻和暖如春脓诡,著一層夾襖步出監(jiān)牢的瞬間无午,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工祝谚, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宪迟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓交惯,卻偏偏與公主長得像次泽,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子席爽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容