千家信息网

如何快速定位Android启动耗时问题

发表于:2024-10-18 作者:千家信息网编辑
千家信息网最后更新 2024年10月18日,本篇内容主要讲解"如何快速定位Android启动耗时问题",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何快速定位Android启动耗时问题"吧!1. 接
千家信息网最后更新 2024年10月18日如何快速定位Android启动耗时问题

本篇内容主要讲解"如何快速定位Android启动耗时问题",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何快速定位Android启动耗时问题"吧!

1. 接入Tencent Matrix

1.1 在你项目根目录下的 gradle.properties 中配置要依赖的 Matrix 版本号,如:

MATRIX_VERSION=1.0.0

1.2 在你项目根目录下的 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 实现 PluginListener,接收 Matrix 处理后的数据, 如:

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 实现动态配置接口, 可修改 Matrix 内部参数. 在 sample-android 中 我们有个简单的动态接口实例DynamicConfigImplDemo.java, 其中参数对应的 key 位于文件 MatrixEnum中, 摘抄部分示例如下:

  class MatrixConfig : IDynamicConfig {    val isFPSEnable: Boolean        get() = trueval isTraceEnable: Boolean        get() = trueval 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 选择程序启动的位置对 Matrix 进行初始化,如在 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()调用卡顿方法

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 = trueval activityThreadValue = field[forName]          val mH = forName.getDeclaredField("mH")          mH.isAccessible = trueval handler = mH[activityThreadValue]          mHandler = handler as Handler      } catch (e: Exception) {      }}

2.4 将原来的onCreate的方法调用转入匿名内部类调用

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

2.5 重写Application onCreate方法

override fun onCreate() {    super.onCreate()    //重点    mHandler.postAtFrontOfQueue(ApplicationTask())}

3.运行,快速定位

3.1 关键字"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

到此,相信大家对"如何快速定位Android启动耗时问题"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

0