溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何快速定位Android啟動(dòng)耗時(shí)問(wèn)題

發(fā)布時(shí)間:2022-03-30 10:55:48 來(lái)源:億速云 閱讀:241 作者:iii 欄目:移動(dòng)開(kāi)發(fā)

本篇內(nèi)容主要講解“如何快速定位Android啟動(dòng)耗時(shí)問(wèn)題”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“如何快速定位Android啟動(dòng)耗時(shí)問(wèn)題”吧!

1. 接入Tencent Matrix

1.1 在你項(xiàng)目根目錄下的 gradle.properties 中配置要依賴的 Matrix 版本號(hào),如:

MATRIX_VERSION=1.0.0

1.2 在你項(xiàng)目根目錄下的 build.gradle 文件添加 Matrix 依賴,如:

dependencies {
      classpath ("com.tencent.matrix:matrix-gradle-plugin:${MATRIX_VERSION}") { changing = true }
  }

1.3 在 app/build.gradle 文件中添加 Matrix 各模塊的依賴,如:

  dependencies {
    implementation group: "com.tencent.matrix", name: "matrix-android-lib", version: MATRIX_VERSION, changing: true
    implementation group: "com.tencent.matrix", name: "matrix-android-commons", version: MATRIX_VERSION, changing: true
    implementation group: "com.tencent.matrix", name: "matrix-trace-canary", version: MATRIX_VERSION, changing: true
    implementation group: "com.tencent.matrix", name: "matrix-resource-canary-android", version: MATRIX_VERSION, changing: true
    implementation group: "com.tencent.matrix", name: "matrix-resource-canary-common", version: MATRIX_VERSION, changing: true
    implementation group: "com.tencent.matrix", name: "matrix-io-canary", version: MATRIX_VERSION, changing: true
    implementation group: "com.tencent.matrix", name: "matrix-sqlite-lint-android-sdk", version: MATRIX_VERSION, changing: true
    implementation group: "com.tencent.matrix", name: "matrix-battery-canary", version: MATRIX_VERSION, changing: true
    implementation group: "com.tencent.matrix", name: "matrix-hooks", version: MATRIX_VERSION, changing: true
  }

  apply plugin: "com.tencent.matrix-plugin"
  matrix {
    trace {
        enable = true	//if you don"t want to use trace canary, set false
        baseMethodMapFile = "${project.buildDir}/matrix_output/Debug.methodmap"
        blackListFile = "${project.projectDir}/matrixTrace/blackMethodList.txt"
    }
  }

1.4 實(shí)現(xiàn) PluginListener,接收 Matrix 處理后的數(shù)據(jù), 如:

class MatrixListener(context: Context?) : DefaultPluginListener(context) {
    companion object {
        const val TAG: String = "Matrix.TestPluginListener"
    }

    override fun onReportIssue(issue: Issue) {
        super.onReportIssue(issue)
        MatrixLog.e(TAG, issue.toString())

    }
}

1.5 實(shí)現(xiàn)動(dòng)態(tài)配置接口, 可修改 Matrix 內(nèi)部參數(shù). 在 sample-android 中 我們有個(gè)簡(jiǎn)單的動(dòng)態(tài)接口實(shí)例DynamicConfigImplDemo.java, 其中參數(shù)對(duì)應(yīng)的 key 位于文件 MatrixEnum中, 摘抄部分示例如下:

  class MatrixConfig : IDynamicConfig {
    val isFPSEnable: Boolean
        get() = true
    val isTraceEnable: Boolean
        get() = true
    val isMatrixEnable: Boolean
        get() = true

    override fun get(key: String, defStr: String): String {

        // for Activity leak detect
        if (ExptEnum.clicfg_matrix_resource_detect_interval_millis.name == key || ExptEnum.clicfg_matrix_resource_detect_interval_millis_bg.name == key) {
            Log.d(
                "DynamicConfig",
                "Matrix.ActivityRefWatcher: clicfg_matrix_resource_detect_interval_millis 10s"
            )
            return TimeUnit.SECONDS.toMillis(5).toString()
        }
        if (ExptEnum.clicfg_matrix_resource_max_detect_times.name == key) {
            Log.d(
                "DynamicConfig",
                "Matrix.ActivityRefWatcher: clicfg_matrix_resource_max_detect_times 5"
            )
            return 3.toString()
        }
        return defStr
    }

    override fun get(key: String, defInt: Int): Int {
        //TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
        if (MatrixEnum.clicfg_matrix_resource_max_detect_times.name == key) {
            MatrixLog.i(TAG, "key:$key, before change:$defInt, after change, value:2")
            return 2 //new value
        }
        if (MatrixEnum.clicfg_matrix_trace_fps_report_threshold.name == key) {
            return 10000
        }
        if (MatrixEnum.clicfg_matrix_trace_fps_time_slice.name == key) {
            return 12000
        }
        if (ExptEnum.clicfg_matrix_trace_app_start_up_threshold.name == key) {
            return 3000
        }
        return if (ExptEnum.clicfg_matrix_trace_evil_method_threshold.name == key) {
            200
        } else defInt
    }

    override fun get(key: String, defLong: Long): Long {
        //TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
        if (MatrixEnum.clicfg_matrix_trace_fps_report_threshold.name == key) {
            return 10000L
        }
        if (MatrixEnum.clicfg_matrix_resource_detect_interval_millis.name == key) {
            MatrixLog.i(TAG, "$key, before change:$defLong, after change, value:2000")
            return 2000
        }
        return defLong
    }

    override fun get(key: String, defBool: Boolean): Boolean {
        //TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
        return defBool
    }

    override fun get(key: String, defFloat: Float): Float {
        //TODO here return default value which is inside sdk, you can change it as you wish. matrix-sdk-key in class MatrixEnum.
        return defFloat
    }

    companion object {
        private const val TAG = "Matrix.DynamicConfigImplDemo"
    }
}

1.6 選擇程序啟動(dòng)的位置對(duì) Matrix 進(jìn)行初始化,如在 Application 的繼承類中, Init 核心邏輯如下:

  Matrix.Builder builder = new Matrix.Builder(application); // build matrix
  builder.patchListener(new TestPluginListener(this)); // add general pluginListener
  DynamicConfigImplDemo dynamicConfig = new DynamicConfigImplDemo(); // dynamic config
  
  // init plugin 
  IOCanaryPlugin ioCanaryPlugin = new IOCanaryPlugin(new IOConfig.Builder()
                    .dynamicConfig(dynamicConfig)
                    .build());
  //add to matrix               
  builder.plugin(ioCanaryPlugin);
  
  //init matrix
  Matrix.init(builder.build());

  // start plugin 
  ioCanaryPlugin.start();

2. 改造Application子類

2.1 模擬Application卡頓

private fun A() {
        B()
        H()
        L()
        SystemClock.sleep(800)
    }

    private fun B() {
        C()
        G()
        SystemClock.sleep(200)
    }

    private fun C() {
        D()
        E()
        F()
        SystemClock.sleep(100)
    }

    private fun D() {
        SystemClock.sleep(20)
    }

    private fun E() {
        SystemClock.sleep(20)
    }

    private fun F() {
        SystemClock.sleep(20)
    }

    private fun G() {
        SystemClock.sleep(20)
    }

    private fun H() {
        SystemClock.sleep(20)
        I()
        J()
        K()
    }

    private fun I() {
        SystemClock.sleep(20)
    }

    private fun J() {
        SystemClock.sleep(6)
    }

    private fun K() {
        SystemClock.sleep(10)
    }


    private fun L() {
        SystemClock.sleep(10000)
    }

2.2 Application.onCreate()調(diào)用卡頓方法

override fun onCreate() {
  A()
}

2.3 反射獲取ActivityThread的mHandler

override fun attachBaseContext(base: Context?) {
      super.attachBaseContext(base)
      println("zijiexiaozhan MyApp attachBaseContext")
      time1 = SystemClock.uptimeMillis()
      time3 = System.currentTimeMillis()

      try {
          val forName = Class.forName("android.app.ActivityThread")
          val field = forName.getDeclaredField("sCurrentActivityThread")
          field.isAccessible = true
          val activityThreadValue = field[forName]
          val mH = forName.getDeclaredField("mH")
          mH.isAccessible = true
          val handler = mH[activityThreadValue]
          mHandler = handler as Handler
      } catch (e: Exception) {
      }
}

2.4 將原來(lái)的onCreate的方法調(diào)用轉(zhuǎn)入匿名內(nèi)部類調(diào)用

inner class ApplicationTask : Runnable {
    override fun run() {
        A()
    }
}

2.5 重寫(xiě)Application onCreate方法

override fun onCreate() {
    super.onCreate()
    //重點(diǎn)
    mHandler.postAtFrontOfQueue(ApplicationTask())
}

3.運(yùn)行,快速定位

3.1 關(guān)鍵字"Trace_EvilMethod"查找日志

tag[Trace_EvilMethod]type[0];key[null];content[{"machine":"MIDDLE","cpu_app":0,"mem":3822452736,"mem_free":1164132,"detail":"NORMAL","cost":1344,"usage":"0.37%","scene":"default","stack":"0,1048574,1,1344 1,5471,1,1338 2,17582,1,1338 3,17558,1,1338 4,17560,1,379 5,17562,1,160 6,17563,1,17 6,17566,1,20 6,17568,1,20 5,17569,1,20 4,17573,1,56 5,17575,1,21 5,17576,1,5 5,17578,1,10 4,17580,1,102 ","stackKey":"17558|","tag":"Trace_EvilMethod","process":"com.peter.viewgrouptutorial","time":1624837969986}]

3.2 解析日志 打印卡頓堆棧

android.os.Handler dispatchMessage 1344
.com.peter.viewgrouptutorial.MyApp$ApplicationTask run 1338
..com.peter.viewgrouptutorial.MyApp access$A 1338
...com.peter.viewgrouptutorial.MyApp A 1338
....com.peter.viewgrouptutorial.MyApp B 379
.....com.peter.viewgrouptutorial.MyApp C 160
......com.peter.viewgrouptutorial.MyApp D 17
......com.peter.viewgrouptutorial.MyApp E 20
......com.peter.viewgrouptutorial.MyApp F 20
.....com.peter.viewgrouptutorial.MyApp G 20
....com.peter.viewgrouptutorial.MyApp H 56
.....com.peter.viewgrouptutorial.MyApp I 21
.....com.peter.viewgrouptutorial.MyApp J 5
.....com.peter.viewgrouptutorial.MyApp K 10
....com.peter.viewgrouptutorial.MyApp L 102

到此,相信大家對(duì)“如何快速定位Android啟動(dòng)耗時(shí)問(wèn)題”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI