Android魔镜:方法耗时统计插件Mirror-基础篇
晓锋,曾在PPTV工作,饿了么资深Android工程师,专注于Android单元测试、架构设计、性能优化、以及最新技术分享,个人博客:michaelzhong。
注:本篇是《Android魔镜:方法耗时统计插件Mirror》系列博客的第一篇,后面我们会持续更新,欢迎关注!
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
文件,如图:
这里需要注意的两点就是:
- 在
build.gradle
配置文件里要引入的插件名是me.ele.mirror.plugin
,即properties
文件名,否则就会找不到插件; implementation-class
配置的是继承于Plugin的入口类,即me.ele.mirror.MirrorPlugin
,没有.groovy
后缀名。
2.9 发布到本地Maven
在plugin
module中,点击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技术。要是有什么不对的地方,请多多指正!最后,非常感谢大家对本篇博客的关注!
参考文献
- github.com/JakeWharton…
- github.com/JakeWharton…
- greenrobot.org/greendao/
- docs.gradle.org/current/use…
阅读博客还不过瘾?
欢迎大家扫二维码通过添加群助手,加入交流群,讨论和博客有关的技术问题,还可以和博主有更多互动
博客转载、线下活动及合作等问题请邮件至 shadowfly_zyl@hotmail.com 进行沟通
Android魔镜:方法耗时统计插件Mirror-基础篇相关推荐
- 神兵利器—Android方法耗时统计插件Mirror(上)
1 前言 1.1 发生背景 有一天,Boss跑过来说,下次迭代我们要做蜂鸟团队App性能调优.对于一个大型成熟的App应用,在业务稳定后,往往会更加关注性能相关的表现.那么,Android App的性 ...
- android 方法统计,神兵利器—Android方法耗时统计插件Mirror(上)
1 前言 1.1 发生背景 有一天,Boss跑过来说,下次迭代我们要做蜂鸟团队App性能调优.对于一个大型成熟的App应用,在业务稳定后,往往会更加关注性能相关的表现.那么,Android App的性 ...
- android前端怎样php后台交互(基础篇)
android前端怎样php后台交互(基础篇) android客户端和php+mysql+apache搭建的服务器之间的简单交互,实现登入功能. 实现原理就是android客户端发送请求,传给服务器登 ...
- 【转载】企业级服务器设计与实现经验之插件系统基础篇
最初之所以要采用插件的形式进行开发,主要是为了解决功能服务的"热插拔"问题,在决定采用"框架+插件"的方式进行设计后,我们就更进一步,打算将一个个可以分割开来的 ...
- Python Qt GUI设计:窗口布局管理方法【强化】(基础篇—6)
目录 1. 水平布局类(QHBoxLayout) 2.垂直布局类(QVBoxLayout) 3.网格布局类(QGridLayout) 3.1.单一的网络布局 3.2.跨越行.列的网络布局 4.表单布局 ...
- 在线地图插件forarcmap_QGIS基础篇插件安装(在线地图纠偏)
QGIS基础篇,可以关注微信公众号,发送关键字获取相关文章. 本文主要介绍,QGIS插件安装,QGIS插件是基于Python和Qt开发的,通过其插件平台,可以安装很多有用的插件. 1. 插件安装,主要 ...
- c# 扩展方法奇思妙用基础篇八:Distinct 扩展(转载)
转载地址:http://www.cnblogs.com/ldp615/archive/2011/08/01/distinct-entension.html 刚看了篇文章 <Linq的Distin ...
- android监控方法耗时开源库,【开源完整项目】 AndroidGodEye 监控Android数据指标
AndroidGodEye Android开发者在性能检测方面的工具一直比较匮乏,仅有的一些工具,比如Android Device Monitor,使用起来也有些繁琐,使用起来对开发者有一定的要求.而 ...
- android图片压缩上传系列-基础篇
开发中遇到需要上传图片的场景还是很常见的,这就涉及到图片的压缩处理.如果不进行压缩,势必造成消耗大量的流量,下载图片的速度慢等. 关于android如何压缩,网上的资料也是很多,但大多数都是代码片段, ...
最新文章
- 五款漂亮的 GNOME 3.4 主题-PPA
- 别骂了,拼多多不挣钱(Doge)
- 屏蔽storm ui的kill功能
- QWidget子窗口中setStyleSheet无效,解决方法
- OpenCASCADE:Foundation Classes库组织
- Java 7:HashMap与ConcurrentHashMap
- SpringBoot自定义Starter(自动配置类)
- C语言和C+的区别是什么?8个点通俗易懂的告诉你
- 华为云数据库首席架构师:关于数据库他这样说……
- SpringBoot整合RabbitMQ-创建队列并绑定交换机
- 虚拟机VMware Workstation与主机间共享文件(利用虚拟光驱)
- JavaWeb学习总结(一)JavaWeb入门与Tomcat
- 确定填充介质的矩形波导单模传输TE10波的工作频率
- Hive基本操作入门
- 配置IIS5.5/6.0 支持 Silverlight
- git提交中target等目录忽略与取消忽略
- Ionic 创建打包项目
- 基于FPGA的卷积神经网络加速器(绪论)
- Mixed Content: The page at 'https://m.ctrip.com/webapp/dingzhi/v3_index' was loa
- 四川托普计算机学校官网,四川中等职业技术学院
热门文章
- 马自达css滑动按钮,css3实现的switch滑动开关按钮的效果
- 用python中的 IDLE编写代码 ,运行代码
- 索引全扫描与索引快速扫描的区别
- 隧道人员定位考勤软件详细介绍
- 服务器上如何连接显示器和键盘,紧急求助,一个电脑主机能接两个显示器和键盘么?...
- 淘米手套游戏CTO潘辉《如何提高手游开发的效率》
- VR影视“万事俱备只欠东风”,它会成为下一个内容发展的风口吗?
- 新记账软件测试工资,【金蝶随手记测试工程师面试】感觉被坑了。-看准网
- FPGA时序约束理论篇之IO约束
- Aigtek线束连接器检测仪_导通检测仪_汽车线束检测仪_瞬断检测仪