曉鋒,曾在PPTV工做,餓了麼資深Android工程師,專一於Android單元測試、架構設計、性能優化、以及最新技術分享,我的博客:michaelzhong。html
注:本篇是《Android魔鏡:方法耗時統計插件Mirror》系列博客的第一篇,後面咱們會持續更新,歡迎關注!java
有一天,Boss跑過來講,下次迭代咱們要作蜂鳥團隊App
性能調優。對於一個大型成熟的App應用,在業務穩定後,每每會更加關注性能相關的表現。那麼,Android App
的性能調優該從什麼地方入手呢?在進行性能調優、減小應用卡頓過程當中,找出問題——耗時嚴重的代碼,是一個不可或缺且很是重要的步驟,纔能有的放矢對症下藥。如何發現應用中的耗時任務甚至是耗時函數呢,若是想依靠開發人員經過review代碼來找出問題多少有點不太現實,要是能夠在日誌中或者報表中羅列出每一個方法的執行時間,絕對是一個高效便捷的功能,對耗時方法一目瞭然。因此,Mirror
工具就應運而生。Mirror
取自「魔鏡」,意爲「魔鏡!魔鏡!照出全部妖魔鬼怪!」android
在此以前,要統計一個函數的執行時間,可能咱們大多數同窗都是這麼作的:在方法調用的先後,手動編寫耗時統計代碼,以下:git
long start = SystemClock.elapsedRealtime();
// 目標方法
doingSomeThing();
Log.d(TAG, "doingSomeThing()[" + (SystemClock.elapsedRealtime() - start) + "ms]");
複製代碼
若是統計一兩個方法的執行時間,徹底能夠應付的過來。可是若是方法比較多,怎麼辦,不可能在每一個方法先後都寫這樣冗餘的代碼吧。一旦接入Mirror,就能夠垂手可得地幫咱們完成冗餘繁瑣的工做。Mirror是一個Android Studio Gradle插件,在編譯時,經過AOP字節碼插入的方式對每個方法插入方法耗時統計代碼。github
此處,可能有同窗會問:Hugo工具也能夠作到方法耗時的統計,爲何要用Mirror呢?在解答以前,先簡單介紹一下Hugo工具。Hugo是國外大佬JakeWharton開發的,經過註解聲明的方式,統計函數的執行時間。仍是以上面的例子來說,導入依賴後,直接在doingSomeThing
方法上添加@DebugLog
註解便可,以下:api
@DebugLog
private void doingSomeThing() {
......
}
複製代碼
所謂成也蕭何,敗也蕭何!經過註解聲明的方式,統計一兩個方法耗時倒也方便,要是統計全部方法耗時就沒法勝任,不可能註解滿天飛吧。再者,註解聲明要是多了,代碼編譯的效率也就下降。所以,Hugo工具只適合有針對性地統計少數方法的耗時。性能優化
在開發實現Mirror
工具中,涉及到Gradle插件開發和Aop字節碼插入,咱們將以上下兩篇博客的形式來說解,本篇重點是Gradle插件開發。服務器
Mirror
是在編譯時藉助於Gradle 插件,利用Aop字節碼插入技術,從而幫助咱們能夠自動地往每一個方法插入方法耗時統計的代碼。不一樣於Eclipse,Android Studio開發工具爲咱們提供了Gradle Plugin方式,能夠自定義Task在編譯時期完成咱們制定好的任務。目前,咱們常常用的ButterKnife、GreenDao工具都用到了Gradle插件。自定義Gradle插件,是Android開發人員不可缺乏的一項技能,顯得特別基礎重要,是時候要學習一波了。架構
基於Mirror爲例子,帶領你們自定義Gradle插件app
如圖新建一個MirrorDemo工程,若是是在原有的Project上開發,這一步就能夠跳過。
在Project裏新建一個Module,這裏取名爲"plugin",如圖。這個Module用於開發Gradle插件,一樣Module裏面並無Gradle Plugin給你選,可是咱們只是須要一個「容器」來容納咱們寫的插件。所以,你能夠隨便選擇一個Module類型(如Phone、Tablet Module、Android Library),由於在下一步咱們是將裏面的大部份內容刪除,因此選擇哪一個類型的Module不重要。
將剛纔新建的Module中把內容刪除,只保留build.gradle
文件和src/main
目錄。
因爲Gradle是基於groovy語言,所以咱們開發的Gradle插件至關於一個groovy項目。因此,須要在main目錄下新建groovy目錄。
配置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()
}
複製代碼
爲了方便管理和引用,就要把插件打包發佈到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"
}
}
複製代碼
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("========================");
}
}
複製代碼
在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
後綴名。在plugin
module中,點擊Tasks目錄下的uploadArchives
發佈依賴到repo倉庫中,如圖:
在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'
複製代碼
build項目後,能夠在Gradle Console窗口中看到輸出內容:
經過以上步驟,咱們已經實現了自定義Gradle插件。雖然只是一個Demo,可是在看到控制檯下打印出自定義的log,心中仍是有很大的成就感,畢竟咱們接觸到了一個新姿式。
本篇博客主要是帶領你們一步步手動自定義一個Gradle插件,是實現Mirror工具的基礎,下一篇博客將主要講Mirror工具中涉及的Aop技術。要是有什麼不對的地方,請多多指正!最後,很是感謝你們對本篇博客的關注!
閱讀博客還不過癮?
歡迎你們掃二維碼經過添加羣助手,加入交流羣,討論和博客有關的技術問題,還能夠和博主有更多互動
博客轉載、線下活動及合做等問題請郵件至 shadowfly_zyl@hotmail.com 進行溝通