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

索引

Android中的App啟動,是從用戶點擊應用圖標的那一刻起,到應用界面顯示出來的過程。這段過程有的應用耗時少工秩,有的應用則耗時多,如果我們想要對那些耗時多的應用進行優(yōu)化。那么助币,首先我們需要知道從應用圖標被點擊浪听,到界面加載出來發(fā)生了什么。然后眉菱,我們需要知道這段過程中為什么會發(fā)生部分耗時長的操作迹栓,最后,我們需要知道如何優(yōu)化一款App的啟動速度

目錄

  1. 應用圖標被點擊到界面加載出來的過程
  2. 啟動中出現(xiàn)的問題及其原因
  3. 常用的啟動優(yōu)化手段

1. App的啟動過程

1.1 App的點擊時的啟動邏輯

首先俭缓,我們要知道Android系統(tǒng)的桌面就是一個應用迈螟,我們的應用圖標在桌面上的那個界面其實就是一個Activity,當我們的應用圖標被點擊時尔崔,就觸發(fā)了這個Activity的點擊事件

位于com.android.launcher2包下

public final class Launcher extends Activity

當點擊Activity界面上的一個item(也就是一款應用的icon)的時候答毫,會調用它的onClick方法

public void onClick(View v) {

    if (v.getWindowToken() == null) {
        return;
    }
    if (!mWorkspace.isFinishedSwitchingState()) {
        return;
    }
    Object tag = v.getTag();
    if (tag instanceof ShortcutInfo) {
        ...
        //這里是啟動Activity
        boolean success = startActivitySafely(v, intent, tag);
        if (success && v instanceof BubbleTextView) {
            mWaitingForResume = (BubbleTextView) v;
            mWaitingForResume.setStayPressed(true);
        }
    } ...
}

上面代碼較多,所以省去其他的邏輯季春,只需要看到其中一行調用startActivitySafely洗搂,就是啟動Activity

boolean startActivitySafely(View v, Intent intent, Object tag) {
    boolean success = false;
    try {
        success = startActivity(v, intent, tag);
    } catch (ActivityNotFoundException e) {
        Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
        Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
    }
    return success;
}
//從startActivitySafely調用而來的
boolean startActivity(View v, Intent intent, Object tag) {
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    try {

        boolean useLaunchAnimation = (v != null) &&
                !intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
        UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
        LauncherApps launcherApps = (LauncherApps)
                this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
        if (useLaunchAnimation) {
            ...
        } else {
            if (user == null || user.equals(android.os.Process.myUserHandle())) {
                //這里是真正啟動Activity的代碼
                startActivity(intent);
            } else {
                launcherApps.startMainActivity(intent.getComponent(), user,
                        intent.getSourceBounds(), null);
            }
        }
        return true;
    } catch (SecurityException e) {
       ...
    }
    return false;
}

從startActivitySafely到startActivity,最終會調用到Activity中的startActivity(intent)方法载弄,這個方法就和平時啟動Activity是一樣的

1.2 startActivity的調用步驟

  1. 這時的startActivity會開啟一個新的app
  2. 首先會加載一個main函數(shù)耘拇,并分配一些內(nèi)存區(qū)域(包括方法區(qū),堆區(qū)和java棧)
  3. java棧中會調用到ActivityThread中的main函數(shù)宇攻,實例化一個Application
  4. 調用Application的onCreate方法
  5. 開啟MainActivity

2 啟動中出現(xiàn)的問題及其原因

2.1 啟動白屏

白屏:是由于AppCompat的主題屬性:windowBackgroud導致的惫叛,他是一個白色的背景

3 啟動優(yōu)化手段

3.1 啟動速度

通過Display這個關鍵字,就可以在log里獲取到系統(tǒng)打印的啟動時間

3.1.1 啟動速度測試

adb shell am start -W 包名/全類名
參考對比:QQ
adb shell am start -W com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity
啟動時就會有時間
調用這句命令時逞刷,會走到這個方法

//AM.java
result = mAm.startActivityAndWait(null, null, intent, mimeType,
null, null, 0, mStartFlags, profilerInfo, null, mUserId);
//返回的result里面嘉涌,就有時間信息

3.2.1 啟動速度相關時間

WaitTime

startTime記錄的剛準備調用startActivityAndWait()的時間點
endTime記錄的是startActivityAndWait()函數(shù)調用返回的時間點
WaitTime = startActivityAndWait()調用耗時。

ThisTime和TotalTime

解釋下代碼里curTime夸浅、displayStartTime仑最、mLaunchStartTime三個時間變量.
curTime表示該函數(shù)調用的時間點.
displayStartTime表示一連串啟動Activity中的最后一個Activity的啟動時間點.
mLaunchStartTime表示一連串啟動Activity中第一個Activity的啟動時間點

正常情況下點擊桌面圖標只啟動一個有界面的 Activity,此時 displayStartTime 與mLaunchStartTime 便指向同一時間點帆喇,此時 ThisTime=TotalTime警医。另一種情況是點擊桌面圖標應用會先啟動一個無界面的 Activity 做邏輯處理,接著又啟動一個有界面的Activity坯钦,在這種啟動一連串 Activity 的情況下(知乎的啟動就是屬于這種情況)预皇,displayStartTime 便指向最后一個 Activity 的開始啟動時間點,mLaunchStartTime 指向第一個無界面Activity的開始啟動時間點婉刀,此時 ThisTime吟温!=TotalTime。

一個應用 Activity pause 的耗時路星。也就是說溯街,開發(fā)者一般只要關心 TotalTime 即可诱桂,這個時間才是自己應用真正啟動的耗時洋丐。
最后總結一下呈昔,如果只關心某個應用自身啟動耗時,參考TotalTime友绝;如果關心系統(tǒng)啟動應用耗時堤尾,參考WaitTime;如果關心應用有界面Activity啟動耗時迁客,參考ThisTime

ThisTime郭宝、TotalTime 的計算在 frameworks\base\services\core\java\com\android\server\am\ActivityRecord.java 文件的 reportLaunchTimeLocked() 函數(shù)中

3.2 主題優(yōu)化(簡單)

給splash界面設置主題。例如app啟動時啟動的是AActivity掷漱,那么就給AActivity設置一個單獨的主題Launch
然后在AActivity的onCreate方法中粘室,在super.onCreate之前,將主題還原

<!--APP的基礎主題-->
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
<!--APP的啟動時使用的主題-->
<style name="LaunchTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:windowBackground">@drawable/bg</item>
</style>

然后在第一個顯示的activity中卜范,將主題替換回來

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState)
    Thread.sleep(2000)//do something
    setTheme(R.style.AppTheme);
    setContentView(R.layout.activity_main)
}

這樣使用衔统,就可以避免app在啟動時,耗時過長導致的白屏問題海雪。當然锦爵,也可以不使用特定的背景,而使用透明背景奥裸,也是可行的险掀。例如

<!--APP的啟動時使用的主題-->
<style name="LaunchTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="android:windowIsTranslucent">true</item>
</style>

3.3 trace文件優(yōu)化

File file = new File(Environment.getExternalStorageDirectory(), "app7");
Debug.startMethodTracing(file.getAbsolutePath());
//執(zhí)行方法
Debug.stopMethodTracing()

通過startMethodTracing方法可以獲取trace文件,來分析方法執(zhí)行的時機和次數(shù)
對于那些耗時較長的方法湾宙,可以通過以下幾種方式優(yōu)化
1樟氢、子線程
2、懶加載
對于那些耗時特別長的方法侠鳄,可以具體分析嗡害,優(yōu)化代碼

總結

到此,App啟動也基本總結完了畦攘,最好還是那一句霸妹,良好的代碼習慣才是最重要的

注:此文屬作者原創(chuàng),轉載請標明出處

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末知押,一起剝皮案震驚了整個濱河市叹螟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌台盯,老刑警劉巖罢绽,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異静盅,居然都是意外死亡良价,警方通過查閱死者的電腦和手機寝殴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來明垢,“玉大人蚣常,你說我怎么就攤上這事∪” “怎么了抵蚊?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長溯革。 經(jīng)常有香客問我贞绳,道長,這世上最難降的妖魔是什么致稀? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任冈闭,我火速辦了婚禮,結果婚禮上抖单,老公的妹妹穿的比我還像新娘萎攒。我一直安慰自己,他們只是感情好臭猜,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布躺酒。 她就那樣靜靜地躺著,像睡著了一般蔑歌。 火紅的嫁衣襯著肌膚如雪羹应。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天次屠,我揣著相機與錄音园匹,去河邊找鬼。 笑死劫灶,一個胖子當著我的面吹牛裸违,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播本昏,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼供汛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了涌穆?” 一聲冷哼從身側響起怔昨,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宿稀,沒想到半個月后趁舀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡祝沸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年矮烹,在試婚紗的時候發(fā)現(xiàn)自己被綠了越庇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡奉狈,死狀恐怖卤唉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嘹吨,我是刑警寧澤搬味,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布境氢,位于F島的核電站蟀拷,受9級特大地震影響,放射性物質發(fā)生泄漏萍聊。R本人自食惡果不足惜问芬,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望寿桨。 院中可真熱鬧此衅,春花似錦、人聲如沸亭螟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽预烙。三九已至墨微,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間扁掸,已是汗流浹背翘县。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谴分,地道東北人锈麸。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像牺蹄,于是被迫代替她去往敵國和親忘伞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

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