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上开发,这一步就可以跳过。

Mirror-Demo-Project.png

2.2 新建Module

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

Mirror-Demo-Module.png

2.3 删除其他配置

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

Mirror-Demo-Delelte.png

2.4 新建groovy目录

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

Mirror-Demo-Groovy.png

2.5 配置build.gradle

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

apply plugin: 'groovy'

dependencies {

compile gradleApi() //gradle sdk

compile localGroovy() //groovy sdk

compile '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.mirror

import org.gradle.api.Plugin

import org.gradle.api.Project

public class MirrorPlugin implements Plugin {

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文件,如图:

Mirror-Demo-Properties.png

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

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

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

2.9 发布到本地Maven

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

Mirror-Demo-Upload.png

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窗口中看到输出内容:

Mirror-Demo-Build.png

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

3 小结

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

参考文献

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

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

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

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

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

  3. aop统计请求数量_Spring-Boot+AOP+统计单次请求方法的执行次数和耗时情况-Go语言中文社区...

    本篇结合aop(面向切面编程)的特性,对spring-boot项目下后端开发人员所关心的java代码的性能做了一次简单的统计,比如,前端发了一个post请求(一连串数据的保存),到了后端,首先是指定C ...

  4. 【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行 ( 定义连接点注解 | 定义 Aspect 切面 | 定义切入点 | 逐个处理切入点的各个连接点 )

    文章目录 一.定义 Join Point 连接点注解 二.定义 Aspect 切面 1.定义 Aspect 切面 2.定义 Aspect 切面 3.逐个处理切入点的各个连接点 4.完整 Aspect ...

  5. Android中统计分析的SDK ,友盟统计,百度统计,腾讯统计

    APP统计分析 用户画像 对程序员来说,用户画像就是用户的属性和行为:通俗地说,用户画像是包括了个人信息.兴趣爱好.日常行为等血肉丰满的客户实体.用户画像是精准营销的产物,企业通过收集用户的行为,然后 ...

  6. 百度云api android,帮助文档首页/百度移动统计API/百度移动统计 Android版SDK - 百度开放云平台...

    百度移动统计SDK 一.简介 百度移动统计SDK(Android)是百度官方推出的移动统计SDK在Android平台上的版本(以下简称SDK).SDK的发行版本(完整下载包为android.zip)中 ...

  7. android系统电量优化,基于Android系统网络耗电量优化方法的.pdf

    基于Android系统网络耗电量优化方法的 2012年第10期,第 45卷 通 信 技 术 Vol.45,No.10,2012 总第250期 Communications Technology No. ...

  8. android 交叉编译so,Android交叉编译htop和使用方法

    htop来源于top,top是Unix/linux下功能强大的性能检测工具之一,用于实时检测并统计进程的属性和状态,基于ncurses库,可上显示文字界面.但是top已经非常陈旧,不支持鼠标点击操作, ...

  9. android删除打开方式,Android 打开方式选定后默认了改不回来?解决方法(三星s7为例)...

    Android 打开方式选定后默认了改不回来?解决方法(三星s7为例) 刚刚在测试东西,打开一个gif图,然后我故意选择用支付宝打开,然后...支付宝当然不支持,我觉得第二次打开它应该还会问我,没想到 ...

最新文章

  1. linux 判断网卡类型 有线 无线
  2. DataNumen DWG Recovery中文版
  3. jmr连接mysql_MYSQL 优化之延迟关联
  4. [转]C#读写xml文件
  5. 不使用加减乘除实现加法
  6. python 0o_Python 中的比较:is 与 ==
  7. LeetCode 200. 岛屿数量(图的遍历)
  8. cocos2d-x系列 Mac下配置cocos2d-x开发环境(android和ios)
  9. 2020全球智博会于苏州盛大开幕
  10. c语言如何直接获得键盘反应,c语言获得键盘的按键
  11. Chrome 新功能:因更新或崩溃而重启后,PWA应用将自动恢复运行!
  12. php 设置页面最大执行时间 set_time_limit max_execution_time
  13. 考研数学线上笔记(四):凯哥极限与连续概念选择题系列课程
  14. 关于MVVM的面试问题
  15. Verilog语言注意事项——always
  16. Arduino 下使用ws2812b 16*16 led点阵屏显示汉字,规避FastLED的大坑
  17. [老码团队]ttcn3特性介绍
  18. web前端期末大作业:基于HTML+CSS+JavaScript学校教育主题-卡通风格在线职业教育网页设计 (14页)
  19. SAP R3 功能详解 - 财务管理
  20. ofd在线预览功能开发 前端

热门文章

  1. XC3062A耐压30V锂电池充电IC双灯指示SOT23-6
  2. Android 程序员不得不收藏的 90+ 个人博客(持续更新,android项目实战手机安全卫士
  3. Unity3D 优化总篇
  4. 笔记1:计算机的基本组成
  5. erp5开源制造业erp外协加工设置
  6. html学生选课系统源码,学生选课系统
  7. java计算机毕业设计BS景区票务管理系统设计与实现MyBatis+系统+LW文档+源码+调试部署
  8. 几何原本-欧几里得算法(判断两数是否互质+最大公倍数)代码实现
  9. 中基鸿业投资理财你需要知道的五件事
  10. ubuntu server命令行搭建虚拟专用网