目录前言 1. 接入Tencent Matrix 2. 改造Application子类 3.运行,快速定位 总结前言 Tencent Matrix默认无法监测Application
Tencent Matrix默认无法监测Application冷启动的耗时方法,本文介绍了如何改造Matrix支持冷启动耗时方法监测。让你一分钟就能给App启动卡顿号脉。
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() = 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 选择程序启动的位置对 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.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 = 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 将原来的onCreate的方法调用转入匿名内部类调用
inner class ApplicationTask : Runnable {
override fun run() {
A()
}
}
2.5 重写Application onCreate方法
override fun onCreate() {
super.onCreate()
//重点
mHandler.postAtFrontOfQueue(ApplicationTask())
}
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\n1,5471,1,1338\n2,17582,1,1338\n3,17558,1,1338\n4,17560,1,379\n5,17562,1,160\n6,17563,1,17\n6,17566,1,20\n6,17568,1,20\n5,17569,1,20\n4,17573,1,56\n5,17575,1,21\n5,17576,1,5\n5,17578,1,10\n4,17580,1,102\n","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启动耗时问题的文章就介绍到这了,更多相关定位Android启动耗时内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: 一分钟快速定位Android启动耗时问题
本文链接: https://lsjlt.com/news/129673.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-21
2023-10-28
2023-10-28
2023-10-27
2023-10-27
2023-10-27
2023-10-27
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0