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

栏目: Groovy · 发布时间: 6年前

内容简介:晓锋,曾在PPTV工作,饿了么资深Android工程师,专注于Android单元测试、架构设计、性能优化、以及最新技术分享,个人博客:michaelzhong。注:本篇是《Android魔镜:方法耗时统计插件Mirror》系列博客的第一篇,后面我们会持续更新,欢迎关注!有一天,Boss跑过来说,下次迭代我们要做蜂鸟团队

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

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

2.2 新建Module

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

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

2.3 删除其他配置

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

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

2.4 新建groovy目录

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

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

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

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

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

  1. build.gradle 配置文件里要引入的插件名是 me.ele.mirror.plugin ,即 properties 文件名,否则就会找不到插件;
  2. implementation-class 配置的是继承于Plugin的入口类,即 me.ele.mirror.MirrorPlugin ,没有 .groovy 后缀名。

2.9 发布到本地Maven

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

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

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

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

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


以上所述就是小编给大家介绍的《Android魔镜:方法耗时统计插件Mirror-基础篇》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

面向模式的软件体系结构(卷1) (平装)

面向模式的软件体系结构(卷1) (平装)

Frank Buschmann、Regine meunier、Hans Rohnert、Peter Sommerlad、Michael Stal / 贲可荣、郭福亮 / 机械工业出版社 / 2003-1 / 45.0

一起来看看 《面向模式的软件体系结构(卷1) (平装)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具