在基礎(chǔ)篇中买决,我們介紹了什么是注解以及如何開發(fā)注解處理器讥珍,今天就來(lái)說(shuō)說(shuō)在開發(fā)編譯時(shí)注解處理器中的那些最佳實(shí)踐。
什么是Android-apt
我們知道APT是集成在javac當(dāng)中的工具灼卢,這個(gè)Android-apt又是什么鬼呢? 對(duì)于從事Android開發(fā)的同學(xué)來(lái)說(shuō)练对,ButterKnife這個(gè)開源工具可是非常熟悉。在使用該工具之前吹害,你需要進(jìn)行配置:
compile 'com.jakewharton:butterknife:8.4.0'
apt 'com.jakewharton:butterknife-compiler:8.4.0'
這里的有什么用螟凭?我們?cè)谏弦还?jié)中沒(méi)有配置apt插件照樣可以用,這是怎么一回事它呀?
Anroid-apt是用在Android Studio中處理注解處理的插件螺男。它有兩方面的作用:
- 只允許配置編譯時(shí)注解處理器依賴,但在最終APK或者Library中不包含注解處理器的代碼纵穿。
- 設(shè)置源路徑下隧,以便由注解處理器生成的代碼能被Android Studio識(shí)別。
另外政恍,一些注解處理器可以接受外部的參數(shù)汪拥,在IDEA當(dāng)中我們可以直接配置,但是基于IDEA而來(lái)的Android Studio反而無(wú)法直接配置篙耗,借助Android-apt插件我們可以實(shí)現(xiàn)該功能迫筑,其用法如下:
apt{
arguments{
配置參數(shù)名稱 參數(shù)值
}
}
對(duì)與在一個(gè)jar包中的注解處理器(API和處理器)而言,我們不需要進(jìn)行特殊的配置宗弯,它照樣可以工作脯燃。如果我們需要在項(xiàng)目當(dāng)中引用注解處理器生成的代碼,那么就需要使用Android-apt插件來(lái)幫助解決蒙保。
對(duì)于Butter Knife辕棚,EventBus 3.0這類工具,最終我們都需要在自己項(xiàng)目引用注解處理器生成的代碼邓厕,因此需要為其配置Android-apt逝嚎。EventBus 3.0的注解處理器還接受兩個(gè)參數(shù),當(dāng)然也要借助Android-apt插件了,以EventBus在工程的配置為例:
到現(xiàn)在详恼,我們恍然大霧补君,原來(lái)Android-apt是這么用的啊。知其然更知其所以然啊昧互,現(xiàn)在無(wú)論你遇到什么樣的配置問(wèn)題挽铁,那都是小菜一碟。
你正在為自己明白了Android-apt的用途的時(shí)候敞掘,無(wú)意間聽到了消息:android-apt插件作者近期已經(jīng)發(fā)表聲明表示后續(xù)不會(huì)再繼續(xù)維護(hù)該插件叽掘。
噩耗就是來(lái)的這么隨心所欲啊>裂恪8狻!好不容易懂了,結(jié)果發(fā)現(xiàn)這玩意不再更新疯潭,這是什么梗什么怨啊赊堪。
什么是annotationProcessor
Gradle從2.2版本開始支持annotationProcessor功能來(lái)代替Android-apt面殖。另外竖哩,和android-apt只支持javac編譯器相比,annotationProcessor同時(shí)支持javac和jack編譯器脊僚。
和Android-apt使用相比相叁,annotationProcessor使用更為簡(jiǎn)單,還是以EventBus的配置為例:
不難看出辽幌,使用annotationProcessor更為簡(jiǎn)單增淹。如果你現(xiàn)在的Gradle版本是2.2.X以上,可以考慮替換掉Android-apt了乌企。
如何劃分項(xiàng)目結(jié)構(gòu)
由于編譯時(shí)注解處理器只在編譯過(guò)程中使用虑润,因此我們不希望注解處理器相關(guān)的代碼在最終的APK中存在,這樣能夠有效的較少方法數(shù)加酵。比如我通常在編寫注解Annotation Processor的時(shí)候會(huì)引用javapoet和Guava拳喻,如果將這些代碼也打進(jìn)最終的APK中會(huì)造成方法數(shù)的暴增,因此建議將注解處理器相關(guān)代碼單獨(dú)成為一個(gè)模塊猪腕。
另外為了方面注解被其他工程引用冗澈,通常我也建議將注解的定義單獨(dú)劃分成一個(gè)模塊。
綜上陋葡,我們最終的項(xiàng)目結(jié)構(gòu)如下:
- xxx/xxx-api:主工程/提供api亚亲,Android Library類型
- xxx-compiler:注解處理器模塊,Java Library類型
- xxx-annotations:自定義注解腐缤,Java Library類型
xxx/xxx-api依賴xxx-annotations,xxx-compiler依賴xxx-annotations捌归。這點(diǎn)Butter Knife給我們一個(gè)非常好的示范:
替換jar為moudle依賴
在基礎(chǔ)篇中我們說(shuō)道,最終要講注解處理器打成jar包岭粤。這樣太麻煩了惜索,總不能每次修改都要重新打個(gè)jar包吧,然后拷貝吧?
其實(shí)在Android Studio當(dāng)中我們同樣可以采用moudle依賴的形式绍在,這和我們以前依賴其他模塊并沒(méi)有太大的區(qū)別门扇,比如我們?cè)谛枰⒔馓幚砥鞯牡胤揭蕾嘺pt即可:
compile project(":apt")
但要在注解處理器moudle中的build.gradle文件中,配置:
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
但是這樣我們的注解處理器就會(huì)被打包到apk當(dāng)中偿渡,現(xiàn)在就可以利用上面說(shuō)的Android-apt了臼寄。
使用@AutoService注解簡(jiǎn)化配置
在基礎(chǔ)篇中,我們說(shuō)道需要注冊(cè)處理器溜宽,雖然沒(méi)什么難度吉拳,但是弄不好一個(gè)粗心就寫錯(cuò)了,有沒(méi)有什么更好的方式呢适揉?
剛寫Google為我們提供的@AutoService留攒,該注解可以方便的生成 META-INF/services/中注解的配置信息煤惩。
首先需要添加依賴:
compile 'com.google.auto.service:auto-service:1.0-rc2'
接起來(lái)在你的注解處理器類上使用@AutoService注解即可,如:
@AutoService(PrintProcessor.class)
public class PrintProcessor extends AbstractProcessor {
//...省略相關(guān)代碼
}
使用非常簡(jiǎn)單不是么炼邀,無(wú)需再關(guān)注 META-INF/services/的創(chuàng)建以注解處理器的注冊(cè)了魄揉,簡(jiǎn)直棒呆了。關(guān)于該注解更多的信息請(qǐng)查看github:https://github.com/google/auto/tree/master/service
如何調(diào)試注解處理器
對(duì)于編譯時(shí)注解處理器的調(diào)試顯得略微麻煩些拭宁,不同構(gòu)建方式(Maven洛退,Ant,Gradle等)會(huì)稍微有些區(qū)別杰标,但也只是形勢(shì)上的區(qū)別兵怯,本質(zhì)上還是離不開JPDA。
編譯時(shí)注解處理器是運(yùn)行在一個(gè)單獨(dú)的JVM當(dāng)中腔剂,因此我們想要對(duì)它進(jìn)行調(diào)試可以使用Remote Debug媒区。無(wú)論是是Eclipse中還是,IDEA當(dāng)中掸犬,對(duì)Remote Debug功能都提供了良好的支持袜漩,作為IDEA二次開發(fā)出的Android Studio同樣也不例外。先來(lái)看一下如何開啟JVM的遠(yuǎn)程調(diào)試功能登渣,在啟動(dòng)JVM的時(shí)候加上以下參數(shù)即可:
//jdk 1.5以前寫法噪服,當(dāng)然該命令是先后兼容的
-J-Xdebug -J-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
//jdk 1.5及以后版本寫法
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
這些參數(shù)的含義這里不錯(cuò)細(xì)說(shuō),你唯一要做的就是修改address指定一個(gè)端口號(hào)∈ぜ耄現(xiàn)在我們以Android Studio中調(diào)試注解處理器為例粘优。
首先在gradle.properties中配置一下參數(shù):
org.gradle.daemon=true
org.gradle.jvmargs=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
接下來(lái)在控制臺(tái)當(dāng)中使用gradle --daemon
命令來(lái)啟動(dòng)守護(hù)線程.
到現(xiàn)在為止在注解處理器工程中的配置已經(jīng)完成了。
接下來(lái)就需要在Android Studio中建立Remote Debugger呻顽,操作步驟如下:
這里的端口號(hào)要保持一致雹顺,不然Remote Debugger是連不上gradle的守護(hù)線程的.設(shè)置完成后該Remote Debugger就可以成功的鏈接到deamon線程了.
準(zhǔn)備工作完成,下面就可以來(lái)調(diào)試了(別忘記加斷點(diǎn))廊遍。具體怎么做呢嬉愧?很簡(jiǎn)單,就是重新編譯即可喉前。這里為了方便演示,直接圖形化操作:
在構(gòu)建過(guò)程中,Remote Debugger將會(huì)觸發(fā)斷點(diǎn)并掛起構(gòu)建過(guò)程,接下來(lái)就可以像往常一樣調(diào)試了.
關(guān)于注解處理的調(diào)試就到這里没酣,其他工具大同小議,在這里就不做說(shuō)明了卵迂。
總結(jié)
有關(guān)注解開發(fā)裕便,調(diào)試方面的問(wèn)題我們已經(jīng)說(shuō)的差不多了。在這2016年的最后一天见咒,我們來(lái)年再見偿衰。