Android性能優化--啓動優化

1. 前言

一個應用App的啓動速度可以影響用戶的首次體驗,啓動速度較慢(感官上)的應用可能致使用戶再次開啓App的意圖降低,或者卸載放棄該應用程序。本文會經過如下幾個方面來介紹應用啓動的相關指標和優化,提供應用的啓動速度。html

總體文章思路以下:python

啓動優化

2. 冷啓動&熱啓動

一般來講,啓動方式分爲兩種:冷啓動和熱啓動。android

  1. 冷啓動:當啓動應用時,後臺沒有該應用的進程,這時系統會從新建立一個新的進程分配給該應用,這個啓動方式就是冷啓動。
  2. 熱啓動:當啓動應用時,後臺已有該應用的進程(例:按back鍵、home鍵,應用雖然會退出,可是該應用的進程是依然會保留在後臺,可進入任務列表查看),因此在已有進程的狀況下,這種啓動會從已有的進程中來啓動應用,這個方式叫熱啓動。

二者之間的特色以下:程序員

  • 冷啓動:系統會從新建立一個新的進程分配給該應用,從Application建立到UI繪製等相關流程都會執行一次。
  • 熱啓動:應用還在後臺,所以該啓動方式不會重建Application,只會從新繪製UI等相關流程。

冷熱啓動時間的計算命令:面試

adb shell am start -W [packageName]/[packageName.XxxActivity]
  • 參數說明:
    一、ThisTime:通常和TotalTime時間同樣。除非在應用啓動時開了一個透明的Activity預先處理一些事再顯示出主Activity,這樣將比TotalTime小。
    二、TotalTime:應用的啓動時間。包含建立進程+Application初始化+Activity初始化到界面顯示。
    三、WaitTime:通常比TotalTime大點,包含系統影響的耗時。
    對於咱們的應用來講結果以下:
  • 冷啓動

冷啓動

  • 熱啓動

熱啓動

能夠看到二者時間相差比較大。
根據該命令基本能夠看出一個應用的啓動速度了,從冷啓動熱啓動的相關關係,當咱們須要優化啓動速度的時候,優化冷啓動速度便可。
可是該命令咱們只是大概知道應用的啓動速度,但並不知道咱們的應用具體哪一個位置耗時,影響啓動速度,後續我會介紹如何獲取啓動具體耗時時間。shell

3. 常規獲取時間方法

常規獲取時間方法無非就是在方法執行前記錄下時間,在方法執行完畢後記錄時間,二者時間之差就是該方法執行的時間,封裝一個基礎類以下:編程

public class LaunchTimer {

 private static final String TAG = "LaunchTimer";
 private static long sTime;

 public static void startRecord() {
 sTime = System.currentTimeMillis();
 }

 public static void endRecord() {
 long cost = System.currentTimeMillis() - sTime;
 NLog.i(TAG, "執行耗時:%s", cost);
 }

}

使用方式以下,能夠直觀的看出createController方法執行的時間微信

createController耗時

這樣已經很直觀了,能夠具體到該方法的執行時間,若是要繼續分析則對該方法內部繼續執行該代碼便可。可是這裏有一個問題若是要知道10個或者更多方法的執行時間,這個方法看起來是能夠,但寫起來過於繁瑣,且不符合程序員的習慣,關於這種場景後面會介紹如何處理。架構

4. TraceView和SysTrace工具使用

  • TraceView使用:TraceView是Android平臺配備一個很好的性能分析工具,它能夠經過圖形化的方式讓咱們瞭解咱們要跟蹤的程序的性能,而且能具體到方法。
    使用方式:
  1. 經過Android studio自帶的traceview查看(Android profiler)。
  2. 經過Android SDK自帶的Debug。
  3. 經過DDMS中的traceview查看。
    本文主要介紹第二種方式,經過sdk中的方法,對應用進行打點獲取相關信息:
@Override
 public void onCreate(final Bundle icicle) {
 setTheme(R.style.BrowserTheme);
 Intent intent = getIntent();
 NLog.i(LOGTAG,"onCreate");
 super.onCreate(icicle);
 //開始記錄,且該方法能夠設置文件大小和路徑
 Debug.startMethodTracing("browser.trace");
 Controller controller=createController();
 mController = controller;
 getWindow().getDecorView().setSystemUiVisibility(
 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN|View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
 controller.handleThirdPartyIntent(intent);
 //結束記錄
 Debug.stopMethodTracing();
 }

如上能夠在目錄下能夠生成以下文件併發

/sdcard/Android/data/com.xxx.xx.browser/files/browser.trace

導出改文件,經過Android Studio的profile打開改文件

traceview

1處能夠看出有多少線程。
2處能夠看出具體方法的耗時。
3處有兩個選項:

  • wall clock time:代碼在線程上執行的真正時間[有一部分是等待cpu輪詢時間]
  • thread time :cpu執行的時間
    通常是優化的是cpu執行時間
    結合業務代碼走查發現Controller0線程爲一個線程,所以主線程一些操做能夠放進去執行,從而減小main線程的耗時。走查代碼能夠發如今Controller0線程中執行以下
requestPermission();
 ExecutorService service = Executors.newSingleThreadExecutor(new NamedThreadFactory("Controller"));
 Future<Boolean> future = service.submit(new Callable<Boolean>() {
 @Override
 public Boolean call() throws Exception {
 try {
 asyncInit();

 } catch (Exception e) {
 return false;
 }
 return true;
 }
 });

requestPermission()方法執行在main線程中,所以咱們能夠把其放在Controller0線程中執行,從而減小main線程的的時間

ExecutorService service = Executors.newSingleThreadExecutor(new NamedThreadFactory("Controller"));
 Future<Boolean> future = service.submit(new Callable<Boolean>() {
 @Override
 public Boolean call() throws Exception {
 try {
 requestPermission();
 asyncInit();

 } catch (Exception e) {
 return false;
 }
 return true;
 }
 });

經測試發現無問題,且對比此時的trace文件發現修改先後main線程時間相對來講減小不少。

  • SysTrace使用:
    SysTrace用於收集可幫助您檢查原生系統進程的詳細系統級數據,例如CPU調度、磁盤活動、應用線程等,並解決掉幀引發的界面卡頓。
    使用方式:

在代碼的開始位置加上tag

TraceCompat.beginSection("AppOnCreate");

而後指定位置結束

TraceCompat.endSection();

便可以抓取到整個應用在此過程的相關信息,例如在onCreate方法中添加上述兩行代碼,執行相關python命令:

python systrace.py -b 32768 -t 10 -a com.xxx.xxx.browser -o browser.html sched gfx view wm am app

操做相關應用,便可以抓取整個過程的相關信息:

systrace

便可以看到添加的tag「AppOnCreate」,對應的時間信息:

  1. Wall Duration 表明的方法從開始到結束的耗時
  2. CPU Duration 表明CPU的執行時間
    經過這兩個參數能夠看出此流程中執行的時間等相關信息
    咱們都知道CPU是輪詢模式,所以優化的方向能夠說是兩個方向,提升CPU的核數和優化CPU執行的時間。

5. 經過AOP獲取時間

  • AOP:面向切面編程(Aspect-Oriented Programming)。若是說,OOP若是是把問題劃分到單個模塊的話,那麼AOP就是把涉及到衆多模塊的某一類問題進行統一管理。打個比方Android 裏面PMS,AMS都擁有各自的職責,可是他們都須要經過log系統管理log,這就是一種AOP思想。

AspectJ其實是對AOP編程思想的一個實踐,固然,除了AspectJ之外,還有不少其它的AOP實現,例如ASMDex,但目前最好、最方便的,依然是AspectJ。
AspectJ的使用以下:
根目錄gradle下引用:

classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'

app目錄gradle文件下引用:

implementation 'org.aspectj:aspectjrt:1.8.+'

此兩處引用完成以後,就是代碼編寫:

package com.xx.xxx.browser.aspect;

import android.util.Log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class IntercepLifeCycleAOP {
 //獲取該Activity下的全部on開頭的方法耗時
 @Around("execution(* com.xxx.xxx.BrowserActivity.on**(..))")
 public Object getTime(ProceedingJoinPoint joinPoint) {
 Object proceed = null;
 long start = System.currentTimeMillis();
 try {
 proceed = joinPoint.proceed();
 } catch (Throwable throwable) {
 throwable.printStackTrace();
 }
 long end = System.currentTimeMillis();
 Log.d("IntercepLifeCycleAOP", joinPoint.getSignature().getName() + ":執行時間:" + (end - start));
 return proceed;

 }

}

引入以後結果以下:

AspectJ

能夠看到具體方法的耗時。
採用註解方式,其中Around 須要有必定的AspectJ相關的語法

6. 用戶體驗優化

  1. 主題優化:經過給應用設置一個透明主題,在應用啓動完成以後,再給其賦予本該有的主題,經過對啓動頁的主題設置後,就會將白屏/黑屏抹去,用戶點擊App的圖標就展現啓動圖,讓用戶先產生啓動很快的「錯覺」。
  2. 動畫兼容:根據不一樣年代的機型能夠選擇執行或不執行相關動畫,或者延遲其餘相關操做,可根據device-year-class來判斷具體年份
  3. UI佈局優化。

7. 異步加載

1.採用線程加載一些資源,好比sdk初始化,配置信息拉取等相關資源。線程,線程池,IntentServices都可以,配合延遲效果更好。

2.當咱們採用線程之間的可能會存在各線程之間相互等待依賴等相關問題,資源A線程必須在資源B加載完成,才能加載,但二者又會在不一樣的線程之間,此時簡單的辦法能夠採用CountDownLatch來實現。其總體思路以下圖

CountDownLatch

3.使用 Pipeline 機制,根據業務優先級規定業務初始化時機,制定啓動框架,它們爲各個任務創建依賴關係,最終構成一個有向無環圖。對於能夠併發的任務,會經過線程池最大程度提高啓動速度。不管是微信的mmkernel 仍是阿里的Alpha 都具有這種能力。

4.其餘方案:
除了上述幾種,咱們也能夠利用IdealHandler,dex分包等相關方式作到啓動優化。

8. 總結

上面主要介紹瞭如何獲取啓動的相關事件和相關優化知識點。關於時間就是儘可能使用工具,關於優化總體思路就是能預加載能延遲加載的資源儘可能去預加載去延遲加載,能異步的業務儘可能異步。
固然優化這個話題也是要根據具體的業務邏輯來定,總之:

對於啓動優化要警戒 KPI 化,咱們要解決的不是一個數字,而是用戶真正的體驗問題。

上述只是提供一些思路和方式,還有不少奇淫技巧,歡迎給位大佬評論指出。

Android學習PDF+架構視頻+面試文檔+源碼筆記


感謝你們能耐着性子看完囉裏囉嗦的文章

在這裏我也分享一份私貨,本身收錄整理的Android學習PDF+架構視頻+面試文檔+源碼筆記,還有高級架構技術進階腦圖、Android開發面試專題資料,高級進階架構資料幫助你們學習提高進階,也節省你們在網上搜索資料的時間來學習,也能夠分享給身邊好友一塊兒學習

若是你有須要的話,能夠點贊+評論關注我,而後加我VX:15388039515 我發給你
(或關注微信公衆號「Android開發之家」回覆【資料】免費領取)

相關文章
相關標籤/搜索