一个能让你了解所有函数调用顺序以及函数耗时的Android库 (更新版)


作者:zjw-swun

博客:https://juejin.im/user/58994f1d128fe1006cbfe0da

声明:本文由作者 zjw-swun 授权发布,未经原作者允许请勿转载





背景:当项目代码量很大的时候,或者你作为一名新人要快速掌握代码的时候,给函数打上log,来了解代码执行逻辑,这种方式会显然成本太大,要改动项目编译运行,NO!太耗时;或者你想debug的方式来给你想关注的几个函数,来了解代码执行逻辑,NO!因为你肯定会漏掉函数;也许你可以固执的给你写的项目打满log说这样也行,但是你要知道你方法所调用的jdk的函数或者第三方aar或者jar再或者android sdk中的函数调用顺序你怎么办,还能打log吗?显然不行吧,来~这个项目给让可以让你以包名为过滤点过滤你想要知道所有函数调用顺序。

项目地址:https://github.com/zjw-swun/AppMethodOrder 欢迎star 

作者列表(排名按代码贡献时间顺序):二精-霁雪清虹,xingstarx,大精-wing,pighead4u ,Tesla ,lijunjie,三精-虹猫,Harlber

1. 效果奉上

640?wx_fmt=gif

动作简介:首先点击MainActivity的自定义MyTextView然后进入SecondActivity再点击textview之后finish跳转回MainActivity 下面是库处理过所得到的函数调用顺序order.txt文件(我这里屏蔽了jdk函数,第三方库函数,以及android sdk中函数,换句话说我就保留了我自己包名中的函数顺序)

 
 
  1. 832 ent 67593 .....com.zjw.appmethodorder.MainActivity.onClick (Landroid/view/View;)V MainActivity.java

  2. 832 ent 99956 ..........com.zjw.appmethodorder.MainActivity.onPause ()V MainActivity.java

  3. 832 ent 99970 ...........com.zjw.appmethodorder.BaseActivity.onPause ()V BaseActivity.java

  4. 832 ent 100472 ............com.zjw.appmethodorder.BaseActivity.baseOnPause ()V BaseActivity.java

  5. 832 ent 128540 ........com.zjw.appmethodorder.SecondActivity.<init> ()V SecondActivity.java

  6. 832 ent 128562 .........com.zjw.appmethodorder.BaseActivity.<init> ()V BaseActivity.java

  7. 832 ent 213911 ........com.zjw.appmethodorder.SecondActivity.onCreate (Landroid/os/Bundle;)V SecondActivity.java

  8. 832 ent 213928 .........com.zjw.appmethodorder.BaseActivity.onCreate (Landroid/os/Bundle;)V BaseActivity.java

  9. 832 ent 258414 ..........com.zjw.appmethodorder.BaseActivity.baseOnCreate ()V BaseActivity.java

  10. 832 ent 1440503 .........com.zjw.appmethodorder.SecondActivity.onResume ()V SecondActivity.java

  11. 832 ent 1440563 ..........com.zjw.appmethodorder.BaseActivity.onResume ()V BaseActivity.java

  12. 832 ent 1445675 ...........com.zjw.appmethodorder.BaseActivity.baseOnResume ()V BaseActivity.java

  13. 832 ent 2954291 .................com.zjw.appmethodorder.MyTextView.onWindowVisibilityChanged (I)V MyTextView.java

  14. 832 ent 3065664 ........com.zjw.appmethodorder.MainActivity.onStop ()V MainActivity.java

  15. 832 ent 3065701 .........com.zjw.appmethodorder.BaseActivity.onStop ()V BaseActivity.java

  16. 832 ent 3069155 ..........com.zjw.appmethodorder.BaseActivity.baseOnStop ()V BaseActivity.java

  17. 832 ent 3139519 .......com.zjw.appmethodorder.SecondActivity.click (Landroid/view/View;)V SecondActivity.java

  18. 832 ent 3146300 ........com.zjw.appmethodorder.SecondActivity.finish ()V SecondActivity.java

  19. 832 ent 3183478 ..........com.zjw.appmethodorder.SecondActivity.onPause ()V SecondActivity.java

  20. 832 ent 3183498 ...........com.zjw.appmethodorder.BaseActivity.onPause ()V BaseActivity.java

  21. 832 ent 3183843 ............com.zjw.appmethodorder.BaseActivity.baseOnPause ()V BaseActivity.java

  22. 832 ent 3209420 ........com.zjw.appmethodorder.MainActivity.<init> ()V MainActivity.java

  23. 832 ent 3209438 .........com.zjw.appmethodorder.BaseActivity.<init> ()V BaseActivity.java

  24. 832 ent 3283359 ........com.zjw.appmethodorder.MainActivity.onCreate (Landroid/os/Bundle;)V MainActivity.java

  25. 832 ent 3283378 .........com.zjw.appmethodorder.BaseActivity.onCreate (Landroid/os/Bundle;)V BaseActivity.java

  26. 832 ent 3330938 ..........com.zjw.appmethodorder.BaseActivity.baseOnCreate ()V BaseActivity.java

  27. 832 ent 4363295 .....................com.zjw.appmethodorder.MyTextView.<init> (Landroid/content/Context;Landroid/util/AttributeSet;)V MyTextView.java

  28. 832 ent 4436094 ..................com.zjw.appmethodorder.MyTextView.onFinishInflate ()V MyTextView.java

  29. 832 ent 4449689 .........com.zjw.appmethodorder.MainActivity.initView ()V MainActivity.java

  30. 832 ent 4539427 .........com.zjw.appmethodorder.MainActivity.onResume ()V MainActivity.java

  31. 832 ent 4539467 ..........com.zjw.appmethodorder.BaseActivity.onResume ()V BaseActivity.java

  32. 832 ent 4543597 ...........com.zjw.appmethodorder.BaseActivity.baseOnResume ()V BaseActivity.java

  33. 832 ent 4917854 .................com.zjw.appmethodorder.MyTextView.onAttachedToWindow ()V MyTextView.java

  34. 832 ent 4918658 .................com.zjw.appmethodorder.MyTextView.onWindowVisibilityChanged (I)V MyTextView.java

  35. 832 ent 5090653 ...................................com.zjw.appmethodorder.MyTextView.onMeasure (II)V MyTextView.java

  36. 832 ent 5355203 ..................................com.zjw.appmethodorder.MyTextView.onMeasure (II)V MyTextView.java

  37. 832 ent 5456681 .......................................com.zjw.appmethodorder.MyTextView.onSizeChanged (IIII)V MyTextView.java

  38. 832 ent 5467577 ....................................com.zjw.appmethodorder.MyTextView.onLayout (ZIIII)V MyTextView.java

  39. 832 ent 5876623 ...........................................com.zjw.appmethodorder.MyTextView.onDraw (Landroid/graphics/Canvas;)V MyTextView.java

  40. 832 ent 6121967 ........com.zjw.appmethodorder.SecondActivity.onStop ()V SecondActivity.java

  41. 832 ent 6121986 .........com.zjw.appmethodorder.BaseActivity.onStop ()V BaseActivity.java

  42. 832 ent 6123689 ..........com.zjw.appmethodorder.BaseActivity.baseOnStop ()V BaseActivity.java

  43. 832 ent 6127522 ........com.zjw.appmethodorder.SecondActivity.onDestroy ()V SecondActivity.java

  44. 832 ent 6127679 .........com.zjw.appmethodorder.BaseActivity.onDestroy ()V BaseActivity.java

  45. 832 ent 6133301 ..........com.zjw.appmethodorder.BaseActivity.baseOnDestroy ()V BaseActivity.java

2. 原理篇

原理就是基于android sdk中提供的工具----traceview,和dmtracedump。traceview会生成.trace文件,该文件记录了函数调用顺序,函数耗时,函数调用次数等等有用的信息。而dmtracedump 工具就是基于trace文件解析生成报告的工具,好在花了一些时间发现dmtracedump -o 选项,经过研究发现,这玩意输出的内容居然是按逻辑顺序从上到下的。

3. 使用方法(建议使用小工具,废弃原有的两个gradle Task)

注意:请先确保 anroid sdk 中的dmtracedump 工具加入在你的环境变量中 

熟悉appMethodOrder的朋友以前用的是两个gradle Task,由于android studio 3.0掐表操作生成的.trace文件改变了生成位置,android studio 3.0以下版本,默认产生在项目目录\capture\时间.trace,而到了android studio 3.0,windows用户trace文件生成目录以本人为例为:C:\Users\hasee\AppData\Local\Temp\cpu_trace.trace,所以以前用的是两个gradle Task,已经不再适应,考虑到扩展性,建议使用小工具

3.1 生成trace文件的方式

生成trace文件的方式有2种一种是掐表操作,一种是在项目中使用代码操作 先介绍掐表生成trace文件 android studio 3.0以下版本操作如下 第一次点击下图时钟icon代表开始掐表,然后回到您的app,进行您要跟踪函数调用顺序的操作,再次点击下图时钟icon代表结束掐表

640?wx_fmt=png

掐表结束后即会在captures目录生成com.zjw.appmethodorder2017.03.2521.41.trace文件,android studio会默认打开一个可视化窗口

640?wx_fmt=png

android studio 3.0版本操作如下 点击CPU 进入CPU面板,然后选择Instrumented选项(Sampled和Instrumented区别在于,Sampled函数调用采样率低生成的trace文件小,采样率低会造成大部分函数调用顺序漏记,Instrumented相当于无损采样生成文件大),第一次点击下图红色圆形icon代表开始掐表,然后回到您的app,进行您要跟踪函数调用顺序的操作,再次点击下图红色圆形icon代表结束掐表,

640?wx_fmt=png

640?wx_fmt=png

结束掐表就会在C:\Users\hasee\AppData\Local\Temp\cputrace.trace(本人是windows环境,使用windows系统可以参照,使用Mac的同学 cd /private/var/folders在folders 搜索cputrace.trace),存在cputrace.trace时会新建cputrace1.tracecpu_trace2.trace 以此类推 

第二种生成trace文件的方式就是在您的项目代码中使用 android.os.Debug.startMethodTracing();android.os.Debug.stopMethodTracing();,执行完stopMethodTracing将会在您手机app的sdcard下面生成.trace文件

3.2 appMethodOrder小工具使用

将trace文件拖拽到小工具File Path左边区域

640?wx_fmt=png

package name处填入您需要过滤的目标包名,或者填入空串(空串将生成所有线程所有包名的函数调用顺序)

640?wx_fmt=png

如上图所示,查询结构存在四个tab,第一个threadID代表线程id,第二个threadName代表线程名,第三个usecs代表函数耗时,第四个method代表函数名+类名,(查询结果是以时间排序的)

4. 海量信息的处理手段

不难发现trace文件时间越长意味着记录的信息也会越来越多,这时候单纯以包名过滤其实满足不了需求,比如我们想通过3个条件(例如 主线程+含zjw包名的 or android.view)来过滤出结果,以下将给出解决办法。

 appMethodOrder小工具会在该jar所在目录生成appMethodOrderTrace.txt,以文本方式记录查询结果。 我们可以借助数据库这个工具使用查询语句来帮助我们过滤出有用的信息,可以使用以下数据库命令,把appMethodOrderTrace.txt内容导入到数据库表中 //从text 导入数据到 mysql (以下语句在mysql中实验是OK的) truncate table app; LOAD DATA LOCAL INFILE 'C:/Users/hasee/Desktop/appMethodOrderTrace.txt' INTO TABLE app;

640?wx_fmt=png

app表结创建语句如下

 
 
  1. CREATE TABLE `app` (

  2. `threadId` int(11) DEFAULT NULL,

  3. `threadName` varchar(255) DEFAULT NULL,

  4. `usecs` varchar(255) DEFAULT NULL,

  5. `method` varchar(255) DEFAULT NULL,

  6. `className` varchar(255) DEFAULT NULL

  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

查询语句示范 //查询main线程中 自定义包下最耗时的操作(以毫秒为单位,降序) SELECT threadName, usecs/1000, method FROM app WHERE app.threadName = "main" AND method like "%自定义包名%" ORDER BY app.usecs DESC

640?wx_fmt=png

5. 计算得出的函数耗时不是准确的时间

根据官方文档(https://developer.android.com/studio/profile/traceview.html) Interpreted code runs more slowly when profiling is enabled. Don't try to generate absolute timings from the profiler results (such as, "function X takes 2.5 seconds to run"). The times are only useful in relation to other profile output, so you can see if changes have made the code faster or slower relative to a previous profiling run.所知(我也用了代码在函数开头结尾用System.nanoTime()时间相减,发现,生成trace的时候确实会拖慢所以函数的执行时间,比System.nanoTime()时间相减得出的时间差的比较多)。原因是trace过程会整体拖慢JVM执行,因此函数耗时只是一个参考值,比较哪个函数更耗时是可以的。




征稿科技互联网,技术类文章

投稿方式:

发送文章链接地址到邮箱:748778890@qq.com

注明“投稿”,收到会回复哟

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值