1.App啟動(dòng)流程
- 點(diǎn)擊桌面App圖標(biāo)供置,Launcher進(jìn)程采用Binder IPC向system_server進(jìn)程發(fā)起startActivity請(qǐng)求谨湘。
- system_server進(jìn)程接收到請(qǐng)求后,向Zygote進(jìn)程發(fā)送創(chuàng)建進(jìn)程的請(qǐng)求芥丧。
- Zygote進(jìn)程fork出新的子進(jìn)程紧阔,即App進(jìn)程
- App進(jìn)程通過(guò)Binder IPC向system_server進(jìn)程發(fā)起attach Application請(qǐng)求
- system_server進(jìn)程收到請(qǐng)求后,進(jìn)行一系列準(zhǔn)備工作后续担,再通過(guò)Binder IPC向App進(jìn)程發(fā)送scheduleLaunchActivity請(qǐng)求擅耽。
- App進(jìn)程的binder線程(ApplicationThread)在收到請(qǐng)求后,通過(guò)handler向主線程發(fā)送LAUNCHER_ACTIVITY消息物遇。
- 主線程收到Message后乖仇,通過(guò)反射機(jī)制創(chuàng)建目標(biāo)Activity,并回調(diào)Activity.onCreate()等方法询兴。
- 到此乃沙,App便正式啟動(dòng),開始進(jìn)入Activity生命周期蕉朵,執(zhí)行完onCreate/onStart/onResume方法崔涂,UI渲染結(jié)束后便可以看到App的主界面。
2.啟動(dòng)狀態(tài)
應(yīng)用有三種啟動(dòng)狀態(tài)始衅,每種狀態(tài)都會(huì)影響應(yīng)用向用戶顯示所需要的時(shí)間:
-
冷啟動(dòng)
系統(tǒng)不存在App進(jìn)程(App首次啟動(dòng)或App被完全殺死)時(shí)啟動(dòng)App- 第一階段
1冷蚂、加載并啟動(dòng)app
2、啟動(dòng)后立即顯示一個(gè)空白的啟動(dòng)窗口
3汛闸、創(chuàng)建app進(jìn)程 - 第二階段
1蝙茶、創(chuàng)建app對(duì)象
2、啟動(dòng)主線程
3诸老、創(chuàng)建主Activity
4隆夯、加載布局
5、布置屏幕
6别伏、首幀繪制
- 第一階段
-
熱啟動(dòng)
當(dāng)我們按下Home鍵或其它情況app被切換到后臺(tái)蹄衷,再次啟動(dòng)app的過(guò)程。熱啟動(dòng)時(shí)厘肮,系統(tǒng)將activity帶回前臺(tái)愧口,如果應(yīng)用程序的所有activity仍駐留在內(nèi)存中,應(yīng)用不必重復(fù)執(zhí)行對(duì)象初始化类茂、布局加載和繪制耍属。
溫啟動(dòng)
溫啟動(dòng)包含了冷啟動(dòng)的一些操作托嚣,由于app進(jìn)程依然在,溫啟動(dòng)只執(zhí)行冷啟動(dòng)的第二階段厚骗,這代表中它比熱啟動(dòng)有更多的開銷示启。如:用戶按返回鍵退出應(yīng)用,然后又重新啟動(dòng)它领舰;系統(tǒng)回收了app的內(nèi)存夫嗓,然后重新啟動(dòng)app。
3.冷啟動(dòng)耗時(shí)統(tǒng)計(jì)
性能測(cè)試中存在2-5-8原則:2s內(nèi)很快提揍,2~5s 還可以啤月,5~8s 很慢還可以接受,8s糟糕透了劳跃。
Google 提出一項(xiàng)計(jì)劃Android Vitals:冷啟動(dòng)5s內(nèi),溫啟動(dòng)2s內(nèi)浙垫,熱啟動(dòng)1.5s內(nèi)刨仑。
-
系統(tǒng)日志統(tǒng)計(jì)
Android Studio Logcat包含一行輸出,名為Displayed的值夹姥,表示從啟動(dòng)進(jìn)程到屏幕上完成對(duì)應(yīng)Activity繪制所用的時(shí)間杉武。ActivityTaskManager: Displayed com.azxc.easyworkapp.test/com.azxc.easyworkapp.ui.LoginActivity: +1s78ms
-
adb命令統(tǒng)計(jì)
adb shell am start -S -W [packageName]/[activityName]
4.CPU Profile
我們可以通過(guò)CPU Profiler查看應(yīng)用在某段時(shí)間里某個(gè)線程執(zhí)行了哪些方法,并且還定量的展示了執(zhí)行這些方法所耗費(fèi)的時(shí)間及其方法的調(diào)用堆棧辙售。CPU Profile只支持Android 8.0以上轻抱,其它版本可以用Debug API生成trace
public class MyApplication extends Application {
public MyApplication(){
//開始跟蹤
Debug.startMethodTracing("trace");
}
//...
}
public class MainActivity extends AppCompatActivity{
@Override
public void onWindowFocusChanged(booleanhasFocus){
super.onWindowFocusChanged(hasFocus);
//停止跟蹤
Debug.stopMethodTracing();
}
//...
}
運(yùn)行app會(huì)生成.trace文件,用Android Studio打開即可旦部。
5.StrictMode
嚴(yán)苛模式是一個(gè)開發(fā)工具祈搜,能夠檢測(cè)程序中的違例,從而修復(fù)士八。最常用于主線程中磁盤讀寫和網(wǎng)絡(luò)訪問(wèn)容燕。
public class MyApplication extends Application {
public void onCreate() {
if (BuildConfig.DEBUG) {
//線程檢查策略
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads() //讀磁盤
.detectDiskWrites()//寫磁盤
.detectNetwork() //檢查網(wǎng)絡(luò)
.penaltyLog()
.build());
//VM檢查策略
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects() //Sqlite對(duì)象,如cursors
.detectLeakedClosableObjects() //未關(guān)閉的Closeable對(duì)象
.penaltyLog() //違規(guī)打印日志
.penaltyDeath() //違規(guī)崩潰
.build());
}
super.onCreate();
}
//...
}
檢測(cè)項(xiàng)
- ThreadPolicy
- detectAll 檢測(cè)所有潛在的違例
- detectCustomSlowCalls 自定義耗時(shí)操作
- detectDiskReads 讀磁盤
- detectDiskWrites 寫磁盤
- detectNetwork 檢查網(wǎng)絡(luò)
- detectResourceMismatches 檢查資源類型是否匹配
- VmPolicy
- detectAll 檢測(cè)所有潛在的
- detectActivityLeaks 檢測(cè)Activity的泄露
- detectCleartextNetwork 檢測(cè)明文的網(wǎng)絡(luò)
- detectFileUriExposure 檢測(cè)file://或者是content://
- detectLeakedClosableObjects 檢查為管理的Closable對(duì)象
- detectLeakedRegistrationObjects 檢測(cè)需要注冊(cè)類型是否解注
- detectLeakedSqlLiteObjects 檢測(cè)sqlite對(duì)象婚度,如cursors
檢測(cè)到違規(guī)項(xiàng)之后的表現(xiàn)形式
- penaltyDeath crash蘸秘,在所有表現(xiàn)形式最后運(yùn)行,
- penaltyDeathOnNetwork crash,在所有值錢蝗茁,必須調(diào)用detectNetwork去允許這個(gè)醋虏。
- penaltyDialog 彈出dialog
- penaltyDropBox 將日志吸入到dropbox中
- penaltyFlashScreen 屏幕閃爍
- penaltyLog log日志
6.啟動(dòng)優(yōu)化相關(guān)
1.異步加載:耗時(shí)多的加載放到子線程中異步執(zhí)行
2.延遲加載: 非必須的數(shù)據(jù)延遲加載
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
XXX.init();
return false;
}
});
3.提前加載:利用ContentProvider提前進(jìn)行初始化