50. 安卓啓動優化

啓動優化包含app的啓動和單頁面的啓動,今天只說app的啓動,二者優化的邏輯是相同的。

app啓動的三種狀態

冷啓動

此時需要創建進程,表示應用的首次啓動

熱啓動

應用的所有 Activity 仍駐留在內存中,不必重複執行對象初始化、佈局加載和繪製。

溫啓動

如:用戶在退出應用後又重新啓動應用。進程可能未被銷燬,繼續運行,但應用需要執行 onCreate() 從頭開始重新創建 Activity

Google 提出的Android Vitals計劃建議:冷啓動控制在 5 秒內, 溫啓控制在2秒內, 熱啓動控制在1.5 秒內。

app啓動分析

如何查看app啓動時間

Android 4.4(API 級別 19)及更高版本中,logcat 包含一個輸出行,代表從啓動進程到在屏幕上完成對應 Activity 的繪製所用的時間,用“ActivityManager: Displayed”過濾即可


還可以通過adb命令查看

adb shell am start -S -W com.rzm.easy.demo/.MainActivity -c android.intent.category.LAUNCHER -a android.intent.action.MAIN </pre>

啓動完成後,將輸出:

ThisTime: 415 表示一連串啓動Activity的最後一個Activity的啓動耗時
TotalTime: 415  真正啓動的耗時,表示新應用啓動的耗時,包括新進程的啓動和Activity的啓動,但不包括前一個應用Activity pause 的耗時
WaitTime: 437 總的耗時,包括前一個應用Activity pause的時間和新應用啓動的時間;
定位代碼中的耗時情況-CPU Profile
Sample Java Methods

對 Java 方法採樣:在應用的 Java 代碼執行期間,頻繁捕獲應用的調用堆棧。分析器會比較捕獲的數據集, 以推導與應用的 Java 代碼執行有關的時間和資源使用信息。如果應用在捕獲調用堆棧後進入一個方法並在下 次捕獲前退出該方法,分析器將不會記錄該方法調用

Trace Java Methods

跟蹤 Java 方法:在運行時檢測應用,以在每個方法調用開始和結束時記錄一個時間戳。系統會收集並比較這些時間戳,以生成方法跟蹤數據,包括時間信息和 CPU 使用率。

Sample C/C++ Functions,對 C/C++

函數採樣:捕獲應用的原生線程的採樣跟蹤數據。(Android 8.0(API 級別 26)或更高版本)

Trace System Calls

跟蹤系統調用:捕獲非常翔實的細節,以便檢查應用與系統資源的交互情況。可以檢查線程狀態的確切 時間和持續時間、直觀地查看所有內核的 CPU 瓶頸在何處,並添加要分析的自定義跟蹤事件。( Android 7.0(API 級別 24)或更高版本)

profile中會顯示一個這樣的界面


Call Chart

以圖形來呈現方法跟蹤數據或函數跟蹤數據,其中調用的時間段和時間在橫軸上表示(橫軸越長,消耗時間越長),而其被調用方則在縱軸上顯 示。對系統 API 的調用顯示爲橙色,對應用自有方法的調用顯示爲綠色,對第三方 API(包括 Java 語言 API)的調 用顯示爲藍色。 (實際顏色顯示有Bug)



如上圖,自定義Application的 onCreate 調用了 Thread.sleep 耗時爲:3s。
Call Chart 已經比原數據可讀性高很多,但它仍然不方便發現那些運行時間很長的代碼,這時我們便需要使用
Flame Chart。

Flame Chart

提供一個倒置的調用圖表,用來彙總完全相同的調用堆棧。也就是說,將具有相同調用方順序的完全相同的方法或 函數收集起來,並在火焰圖中將它們表示爲一個較長的橫條 。
橫軸顯示的是百分比數值。由於忽略了時間線信息,Flame Chart 可以展示每次調用消耗時間佔用整個記錄時長的 百分比。 同時縱軸也被對調了,在頂部展示的是被調用者,底部展示的是調用者。此時的圖表看起來越往上越窄, 就好像火焰一樣,因此得名: 火焰圖。




耗時最長的爲:Thread.sleep

Top Down Tree

如果我們需要更精確的時間信息,就需要使用 Top Down Tree。 Top Down Tree顯示一個調用列表,在該列表中 展開方法或函數節點會顯示它調用了的方法節點。


對於每個節點,三個時間信息:
Self Time —— 運行自己的代碼所消耗的時間; Children Time —— 調用其他方法的時間; Total Time —— 前面兩者時間之和。
此視圖能夠非常方便看到耗時最長的方法調用棧。

Bottom Up Tree

方便地找到某個方法的調用棧。在該列表中展開方法或函數節點會顯示哪個方法調用了自己。



通過工具可以定位到耗時代碼,然後查看是否可以進行優化。對於APP啓動來說,啓動耗時包括Android系統啓動 APP進程加上APP啓動界面的耗時時長,我們可做的優化是APP啓動界面的耗時,也就是說從Application的構建到 主界的 onWindowFocusChanged 的這一段時間。

Debug API

除了直接使用 Profile 啓動之外,我們還可以藉助Debug API生成trace文件。

public class MyApplication extends Application { 

    public MyApplication() {
        Debug.startMethodTracing("ram"); 
    }
}

public class MainActivity extends AppCompatActivity { 
    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        Debug.stopMethodTracing(); </pre>
    }
}

運行App,則會在sdcard中生成一個rzm.trace文件(需要sdcard讀寫權限)。將手機中的trace文件保存至電 腦,隨後拖入Android Studio即可。

StrictMode嚴苛模式

StrictMode是一個開發人員工具,它可以檢測出我們可能無意中做的事情,並將它們提請我們注意,以便我們能夠
修復它們。
StrictMode最常用於捕獲應用程序主線程上的意外磁盤或網絡訪問。幫助我們讓磁盤和網絡操作遠離主線程,可以 使應用程序更加平滑、響應更快。

public class MyApplication extends Application {
    @Override
    public void onCreate() {
        if (BuildConfig.DEBUG) {
            //線程檢測策略
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads() //讀、寫操作
                    .detectDiskWrites()
                    .detectNetwork() // or .detectAll() for all detectable problems .penaltyLog()
                    .build());
            StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectLeakedSqlLiteObjects() //Sqlite對象泄露
                    .detectLeakedClosableObjects() //未關閉的Closable對象泄露 .penaltyLog() //違規打印日誌
                    .penaltyDeath() //違規崩潰
                    .build());
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章