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

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

内容简介:晓锋,曾在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-基础篇》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Alone Together

Alone Together

Sherry Turkle / Basic Books / 2011-1-11 / USD 28.95

Consider Facebookit’s human contact, only easier to engage with and easier to avoid. Developing technology promises closeness. Sometimes it delivers, but much of our modern life leaves us less connect......一起来看看 《Alone Together》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换