1 前言

1.1 发生背景

有一天,Boss跑过来说,下次迭代我们要做蜂鸟团队App性能调优。对于一个大型成熟的App应用,在业务稳定后,往往会更加关注性能相关的表现。那么,Android App的性能调优该从什么地方入手呢?在进行性能调优、减少应用卡顿过程中,找出问题——耗时严重的代码,是一个不可或缺且非常重要的步骤,才能有的放矢对症下药。如何发现应用中的耗时任务甚至是耗时函数呢,如果想依靠开发人员通过review代码来找出问题多少有点不太现实,要是可以在日志中或者报表中罗列出每个方法的执行时间,绝对是一个高效便捷的功能,对耗时方法一目了然。所以,Mirror工具就应运而生。Mirror取自“魔镜”,意为“魔镜!魔镜!照出所有妖魔鬼怪!”
####1.2 传统方式

在此之前,要统计一个函数的执行时间,可能我们大多数同学都是这么做的:在方法调用的前后,手动编写耗时统计代码,如下:

long start = SystemClock.elapsedRealtime();// 目标方法
doingSomeThing();Log.d(TAG, "doingSomeThing()[" + (SystemClock.elapsedRealtime() - start) + "ms]");

如果统计一两个方法的执行时间,完全可以应付的过来。但是如果方法比较多,怎么办,不可能在每个方法前后都写这样冗余的代码吧。一旦接入Mirror,就可以轻而易举地帮我们完成冗余繁琐的工作。Mirror是一个Android Studio Gradle插件,在编译时,通过AOP字节码插入的方式对每一个方法插入方法耗时统计代码。

1.3 对比Hugo

此处,可能有同学会问:Hugo工具也可以做到方法耗时的统计,为什么要用Mirror呢?在解答之前,先简单介绍一下Hugo工具。Hugo是国外大佬JakeWharton开发的,通过注解声明的方式,统计函数的执行时间。还是以上面的例子来讲,导入依赖后,直接在doingSomeThing方法上添加@DebugLog注解即可,如下:

@DebugLog
private void doingSomeThing() {......
}

所谓成也萧何,败也萧何!通过注解声明的方式,统计一两个方法耗时倒也方便,要是统计所有方法耗时就无法胜任,不可能注解满天飞吧。再者,注解声明要是多了,代码编译的效率也就降低。因此,Hugo工具只适合有针对性地统计少数方法的耗时。

2 Gradle插件

在开发实现Mirror工具中,涉及到Gradle插件开发和Aop字节码插入,我们将以上下两篇博客的形式来讲解,本篇重点是Gradle插件开发。

Mirror是在编译时借助于Gradle 插件,利用Aop字节码插入技术,从而帮助我们可以自动地往每个方法插入方法耗时统计的代码。不同于Eclipse,Android Studio开发工具为我们提供了Gradle Plugin方式,可以自定义Task在编译时期完成我们制定好的任务。目前,我们经常用的ButterKnife、GreenDao工具都用到了Gradle插件。自定义Gradle插件,是Android开发人员不可缺少的一项技能,显得特别基础重要,是时候要学习一波了。

基于Mirror为例子,带领大家自定义Gradle插件

2.1 新建Project

如图新建一个MirrorDemo工程,如果是在原有的Project上开发,这一步就可以跳过。

2.2 新建Module

在Project里新建一个Module,这里取名为"plugin",如图。这个Module用于开发Gradle插件,同样Module里面并没有Gradle Plugin给你选,但是我们只是需要一个“容器”来容纳我们写的插件。因此,你可以随便选择一个Module类型(如Phone、Tablet Module、Android Library),因为在下一步我们是将里面的大部分内容删除,所以选择哪个类型的Module不重要。

2.3 删除其他配置

将刚才新建的Module中把内容删除,只保留build.gradle文件和src/main目录。

2.4 新建groovy目录

由于Gradle是基于groovy语言,因此我们开发的Gradle插件相当于一个groovy项目。所以,需要在main目录下新建groovy目录。

2.5 配置build.gradle

配置Module编译环境,删除build.gradle原有配置,导入Plugin的依赖配置:

apply plugin: 'groovy'dependencies {compile gradleApi()   //gradle sdkcompile localGroovy() //groovy sdkcompile 'com.android.tools.build:gradle:2.3.0'
}
repositories {jcenter()
}

2.6 配置Maven

为了方便管理和引用,就要把插件打包发布到Maven仓库里。可以选择打包到本地,或者是远程服务器中。在build.gradle添加如下配置:

apply plugin: 'maven'def mirror_version = "1.0.0"uploadArchives {repositories.mavenDeployer {repository(url: uri('../repo'))pom.groupId = 'me.ele'pom.artifactId = 'mirror-plugin'pom.version = "$mirror_version"}
}

2.7 创建MirrorPlugin

groovy是基于Java,因此接下来创建groovy的过程跟创建java很类似。在groovy新建包名,如:me.ele.mirror,然后在该包下新建groovy文件,通过new->file->MirrorPlugin.groovy来新建名为MirrorPlugin的groovy文件。

package me.ele.mirrorimport org.gradle.api.Plugin
import org.gradle.api.Projectpublic class MirrorPlugin implements Plugin<Project> {void apply(Project project) {System.out.println("========================");System.out.println("Hello MirrorPlugin!");System.out.println("========================");}
}

2.8 创建properties

在main目录下建立\resources\META-INF\gradle-plugins\me.ele.mirror.plugin.properties文件,如图:


这里需要注意的两点就是:

  1. 在build.gradle配置文件里要引入的插件名是me.ele.mirror.plugin,即properties文件名,否则就会找不到插件;

  2. implementation-class配置的是继承于Plugin的入口类,即me.ele.mirror.MirrorPlugin,没有.groovy后缀名。

2.9 发布到本地Maven

在pluginmodule中,点击Tasks目录下的uploadArchives发布依赖到repo仓库中,如图:

2.10 使用本地仓库

在project 的build.gradle中buildscript中增加本地仓库地址,如下:

// Top-level build file where you can add configuration options common to all sub-projects/modules.buildscript {repositories {google()// 添加本地仓库目录maven {url uri('./repo')}jcenter()}dependencies {classpath 'com.android.tools.build:gradle:3.0.0'// NOTE: Do not place your application dependencies here; they belong// in the individual module build.gradle files// 导入Mirror插件依赖classpath 'me.ele:mirror-plugin:1.0.0'}
}allprojects {repositories {google()maven {url uri('./repo')}jcenter()}
}task clean(type: Delete) {delete rootProject.buildDir
}

然后在app的build.gradle中增加plugin

// 在编译时期,应用Mirror插件
apply plugin: 'me.ele.mirror.plugin'

2.11 build项目
build项目后,可以在Gradle Console窗口中看到输出内容:

通过以上步骤,我们已经实现了自定义Gradle插件。虽然只是一个Demo,但是在看到控制台下打印出自定义的log,心中还是有很大的成就感,毕竟我们接触到了一个新姿势。

3 小结

本篇博客主要是带领大家一步步手动自定义一个Gradle插件,是实现Mirror工具的基础,下一篇博客将主要讲Mirror工具中涉及的Aop技术。要是有什么不对的地方,请多多指正!

读者福利

Android架构师的门槛,有没有免费学习资料?

加入Android高级架构群;1007478004,免费提供视频和资料,一起学习,相互讨论。

神兵利器—Android方法耗时统计插件Mirror(上)相关推荐

  1. android 方法统计,神兵利器—Android方法耗时统计插件Mirror(上)

    1 前言 1.1 发生背景 有一天,Boss跑过来说,下次迭代我们要做蜂鸟团队App性能调优.对于一个大型成熟的App应用,在业务稳定后,往往会更加关注性能相关的表现.那么,Android App的性 ...

  2. Android魔镜:方法耗时统计插件Mirror-基础篇

    晓锋,曾在PPTV工作,饿了么资深Android工程师,专注于Android单元测试.架构设计.性能优化.以及最新技术分享,个人博客:michaelzhong. 注:本篇是<Android魔镜: ...

  3. android 引用非 android 工程,Unity3D调用android方法(非插件方式)

    关于Unity3D工程与android工程的转换与合并,请参考我的另外一篇博客,如果你对Unity3D工程加入到android工程的过程不熟悉,也请先看完下面这篇博客: android与Unity3D ...

  4. Unity3D调用android方法(非插件方式)

    关于Unity3Dproject与androidproject的转换与合并,请參考我的另外一篇博客.假设你对Unity3Dproject增加到androidproject的过程不熟悉.也请先看完以下这 ...

  5. unity无法调用android,Unity3D调用android方法(非插件方式)

    关于Unity3D工程与android工程的转换与合并,请参考我的另外一篇博客,如果你对Unity3D工程加入到android工程的过程不熟悉,也请先看完下面这篇博客: 下面,我们来说说本博客的终端, ...

  6. Android Studio最全插件

    在Android开发中,合理的使用Android Studio插件不但可以提高开发效率,还能从整体上提高代码的质量.下面就Android开发中常见的一些插件做一个整理. 1,GsonFormat Gs ...

  7. Android字节码替换方法,滴滴开源 DroidAssist : 轻量级 Android 字节码编辑插件

    出品 | 滴滴技术 作者 | 江义旺 前言:近日,滴滴发布的开源项目 DroidAssist ,提供了一种简单易用.无侵入.配置化.轻量级的 Java 字节码操作方式,只需要在 XML 配置中添加简单 ...

  8. android 方法统计,Android 利用编译时 注入 统计App内所有方法执行时常,分析ANR

    Git传送门 1.应用场景 Android Studio提供了很多性能分析工具,分析CPU耗时,分析内存,但主要是给我们开发阶段使用,而且应用起来也不方便,如果我们能在APP运行的时候捕获所有方法的时 ...

  9. android 耗时分析,启动耗时分析(四)-具体方法耗时分析

    原创文章,转载请注明出处,多谢! 如果cpu频率.调度 和 compiler filter都一一排除了,没问题.那接下来就看是否有具体方法耗时. 一.常用的分析手段: 1.systrace 这里可按s ...

最新文章

  1. oracle 显示格式化
  2. scanf不可以读空格不可以读string
  3. 怎么用计算机把浓度转换成PH,ph换算(ph和氢离子浓度的换算计算器)
  4. 面试官:说说一条查询SQL的执行过程?
  5. jenkins job config.xml结构
  6. 深度优先搜索(DFS)----------------Tju_Oj_3517The longest athletic track
  7. 放寒假的硕博研究生将经历什么?
  8. 5g理论速度_快看看 5G 的实际网速,失望还是兴奋?
  9. [排版题] 例4.2 叠框
  10. 统计学习(二):统计推断
  11. 网络医疗的进步让智能穿戴设备找到市场新蓝海
  12. JavaScript实现飞机大战小游戏
  13. java rest 知乎_JavaWeb开发之模仿知乎首页完整代码
  14. 彻底掌握Quartus——基础篇
  15. git文件夹不区分大小写_Git区分大小写并且您的文件系统可能不区分大小写-Windows上奇怪的文件夹合并
  16. 莎士比亚名言录(中英对照整理版,加出处by 澈)
  17. linux中负载值为多少正常_Linux系统Load average负载详细解释
  18. 洛谷千题详解 | P1014 [NOIP1999 普及组] Cantor 表【C++、Java语言】
  19. 并行计算机概述--性能和评估标准
  20. 无线授时服务器接LED屏,实现ipad远程无线控制led大屏幕分以下几个步骤!

热门文章

  1. jQuery实现下拉列表的二级联动
  2. 在线提取PDF中图片和文字
  3. 天源财富:英特尔正式发布Tiger Lake-H45高性能移动芯片
  4. IP协议数据报格式详解
  5. MES制造执行系统的6项评定基准,你选对了吗?
  6. 解决 kubesphere安装时 kubelet 启动异常问题
  7. 大众PLC自动控制系统,VASS标准项目应该知道的几个知识点
  8. idea常用的牛逼插件
  9. #Python3中tornado高并发框架
  10. 基于CRU中的tmp数据进行年平均气温分析