Android APT 技術淺談
安卓AOP三劍客: APT, AspectJ, Javassist
Android APT
APT(Annotation Processing Tool 的簡稱),可以在程式碼編譯期解析註解,並且生成新的 Java 檔案,減少手動的程式碼輸入。現在有很多主流庫都用上了 APT,比如 Dagger2, ButterKnife, EventBus3 等
代表框架:
- DataBinding
- Dagger2
- ButterKnife
- EventBus3
- DBFlow
- AndroidAnnotation
專案參考
使用姿勢
1,在android工程中,建立一個java的Module,寫一個類繼承AbstractProcessor
@AutoService(Processor.class) // javax.annotation.processing.IProcessor
@SupportedSourceVersion(SourceVersion.RELEASE_7) //java
@SupportedAnnotationTypes({ // 標註註解處理器支援的註解型別
"com.annotation.SingleDelegate",
"com.annotation.MultiDelegate"
})
public class AnnotationProcessor extends AbstractProcessor {
public static final String PACKAGE = "com.poet.delegate";
public static final String CLASS_DESC = "From poet compiler";
public Filer filer; //檔案相關的輔助類
public Elements elements; //元素相關的輔助類
public Messager messager; //日誌相關的輔助類
public Types types;
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
filer = processingEnv.getFiler();
elements = processingEnv.getElementUtils();
messager = processingEnv.getMessager();
types = processingEnv.getTypeUtils();
new SingleDelegateProcessor().process(set, roundEnvironment, this);
new MultiDelegateProcessor().process(set, roundEnvironment, this);
return true;
}
}
2,在繼承AbstractProcessor類中的process方法,處理我們自定義的註解,生成程式碼:
public class SingleDelegateProcessor implements IProcessor {
@Override
public void process(Set<? extends TypeElement> set, RoundEnvironment roundEnv,
AnnotationProcessor abstractProcessor) {
// 查詢註解是否存在
Set<? extends Element> elementSet =
roundEnv.getElementsAnnotatedWith(SingleDelegate.class);
Set<TypeElement> typeElementSet = ElementFilter.typesIn(elementSet);
if (typeElementSet == null || typeElementSet.isEmpty()) {
return;
}
// 迴圈處理註解
for (TypeElement typeElement : typeElementSet) {
if (!(typeElement.getKind() == ElementKind.INTERFACE)) { // 只處理介面型別
continue;
}
// 處理 SingleDelegate,只處理 annotation.classNameImpl() 不為空的註解
SingleDelegate annotation = typeElement.getAnnotation(SingleDelegate.class);
if ("".equals(annotation.classNameImpl())) {
continue;
}
Delegate delegate = annotation.delegate();
// 新增構造器
MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
.addModifiers(Modifier.PUBLIC);
// 建立類名相關 class builder
TypeSpec.Builder builder =
ProcessUtils.createTypeSpecBuilder(typeElement, annotation.classNameImpl());
// 處理 delegate
builder = ProcessUtils.processDelegate(typeElement, builder,
constructorBuilder, delegate);
// 檢查是否繼承其它介面
builder = processSuperSingleDelegate(abstractProcessor, builder, constructorBuilder, typeElement);
// 完成構造器
builder.addMethod(constructorBuilder.build());
// 建立 JavaFile
JavaFile javaFile = JavaFile.builder(AnnotationProcessor.PACKAGE, builder.build()).build();
try {
javaFile.writeTo(abstractProcessor.filer);
} catch (IOException e) {
e.printStackTrace();
}
}
}
3,在專案Gradle中新增 annotationProcessor project 引用
compile project(':apt-delegate-annotation')
annotationProcessor project(':apt-delegate-compiler')
4,如果有自定義註解的話,建立一個java的Module,專門放入自定義註解。專案與apt Module都需引用自定義註解Module
4-1,主工程:
compile project(':apt-delegate-annotation')
annotationProcessor project(':apt-delegate-compiler')
4-2,apt Module:
compile project(':apt-delegate-annotation')
compile 'com.google.auto.service:auto-service:1.0-rc2'
compile 'com.squareup:javapoet:1.4.0'
5,生成的原始碼在build/generated/source/apt下可以看到
難點
就apt本身來說沒有任何難點可言,難點一在於設計模式和解耦思想的靈活應用,二在與程式碼生成的繁瑣,你可以手動字串拼接,當然有更高階的玩法用squareup的javapoet,用建造者的模式構建出任何你想要的原始碼
優點
它的強大之處無需多言,看代表框架的原始碼,你可以學到很多新姿勢。總的一句話:它可以做任何你不想做的繁雜的工作,它可以幫你寫任何你不想重複程式碼。懶人福利,老司機必備神技,可以提高車速,讓你以任何姿勢漂移。它可以生成任何原始碼供你在任何地方使用,就像劍客的劍,快疾如風,無所不及
我想稍微研究一下,APT還可以在哪些地方使用,比如:Repository層?
APT在Repository層的嘗試
瞭解APT與簡單學習之後,搭建Repository層時,發現有一些簡單,重複模版的程式碼
每一次新增新介面都需要簡單地修改很多地方,能不能把一部分程式碼自動生成,減少改動的次數呢?
Repository層
IRemoteDataSource, RemoteDataSourceImpl
遠端資料來源,屬於網路請求相關
ILocalDataSource, LocalDataSourceImpl
本地資料來源,屬於本地資料持久化相關
IRepository,RepositoryImpl
倉庫代理類,代理遠端資料來源與本地資料來源
Repository層APT設計思路
發現在具體實現類中,大多都是以代理類的形式呼叫:方法中呼叫代理物件,方法名稱與引數,返回值型別都相同。顯然可以進行APT的嘗試
簡單的情況,具體實現類中只有一個代理物件
複雜的情況,有多個代理物件,方法內並有一些變化
期望結果:
- 把RemoteDataSourceImpl自動化生成
- 把LocalDataSourceImpl自動化生成
- 把RepositoryImpl自動化生成
自定義註解設計
要想具體實現類自動生成,首先要知道需要什麼:
- 方便自動生成java檔案的類庫
- 自動生成類名字是什麼
- 需要注入的代理物件
- 讓代理物件代理的方法集
自動生成類名字,代理物件,方法集需要通過自定義註解配置引數的形成,在AbstractProcessor中獲取
Delegate
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface Delegate {
/**
* delegate class package
*/
String delegatePackage();
/**
* delegate class name
*/
String delegateClassName();
/**
* delegate simple name
*/
String delegateSimpleName();
}
SingleDelegate
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface SingleDelegate {
/**
* impl class name
*/
String classNameImpl();
/**
* delegate data
*/
Delegate delegate();
}
MultiDelegate
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface MultiDelegate {
/**
* impl class name
*/
String classNameImpl();
/**
* delegate list
*/
Delegate[] Delegates();
}
處理自定義的註解、生成程式碼
AnnotationProcessor
@AutoService(Processor.class) // javax.annotation.processing.IProcessor
@SupportedSourceVersion(SourceVersion.RELEASE_7) //java
@SupportedAnnotationTypes({ // 標註註解處理器支援的註解型別
"com.annotation.SingleDelegate",
"com.annotation.MultiDelegate"
})
public class AnnotationProcessor extends AbstractProcessor {
public static final String PACKAGE = "com.poet.delegate";
public static final String CLASS_DESC = "From poet compiler";
public Filer filer; //檔案相關的輔助類
public Elements elements; //元素相關的輔助類
public Messager messager; //日誌相關的輔助類
public Types types;
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
filer = processingEnv.getFiler();
elements = processingEnv.getElementUtils();
messager = processingEnv.getMessager();
types = processingEnv.getTypeUtils();
new SingleDelegateProcessor().process(set, roundEnvironment, this);
new MultiDelegateProcessor().process(set, roundEnvironment, this);
return true;
}
}
資料參考
相關推薦
Android APT 技術淺談
安卓AOP三劍客: APT, AspectJ, Javassist Android APT APT(Annotation Processing Tool 的簡稱),可以在程式碼編譯期解析註解,並且生成新的 Java 檔案,減少手動的程式碼輸入。
[技術]淺談初始化語義與賦值語義
真的 class 基本 復制構造函數 spa 數值 復制構造 得到 對數 背景 博主是一個常年使用初始化語義的coder= =,所以經常會遇到這樣的對話 int tmp(0); XXX:誒,你這tmp函數是幹什麽的啊 博主:蛤?我哪裏定義了tmp函數了
Android APP架構淺談(含程式碼)
寫在開頭 不多說,本文圍繞一張圖展開,請查閱,歡迎共同討論,叨擾了。如果你還有什麼需求或者什麼想法,可一起完善此demo一起進步哦!!! 讓我們從library到mouble,讓我們談談我理解的專案的Project架構。 lib-netwo
區塊鏈技術淺談
關於區塊鏈技術的思考 自從比特幣成為全世界的焦點以後,區塊鏈莫名火了起來,無論是金融業還是網際網路企業都在盯著這一領域,各大高校也不甘落後,相繼開設區塊鏈課程和專案,就拿本人就讀的南京郵電大學而言,據我所知研究區塊鏈的專案組就能達到兩位數之多,但是事實上區塊鏈的
快取技術淺談
Linux的Disk Cache 資料庫快取的重要性 Query Cache MySQL Query Cache監控工具 本教程由尚矽谷教育大資料研究院出品,如需轉載請註明來源。
android與java淺談this與activity.this
由於的java是草草的的過了一遍那樣學的 所以對很多概念已經是不太清楚了,這兩天開始看android 然後就發現很多東西有點看著懵逼 ,我是打算通過安卓去鞏固的java的 然後我看到了在活動中使用toast這裡 首先在此之前我的已經手動的寫了一個button的,那麼我希望說單擊butt
Android開發之淺談垃圾回收機制GC以及如何用好GC
一、為什麼需要GC 應用程式對資源操作,通常簡單分為以下幾個步驟: 1、為對應的資源分配記憶體 2、初始化記憶體 3、使用資源 4、清理資源 5、釋放記憶體 應用程式對資源(記憶體使用)管理的方式,常見的一般有如下幾種: 1、手動管理:C,C++ 2、計數管理:COM 3、自動管理:.NET,Java,PH
網頁外掛技術淺談(入門篇)
其實網頁外掛所用的技術很簡單,只不過這是一個技術上的禁區,極少有書籍和資料介紹而已。在繼續往下看之前,你至少需要了解:1.http協議的基本含義2.socket通訊基礎3.一門常規開發語言及軟體開發基礎4.動態網頁技術基礎網頁遊戲採用的通訊協議多種多樣,常見的有:1.純htt
Android學習之淺談對MVC模式和MVP模式的理解
進來聽群裡大神們一直在講MVP模式的好處優點種種…,因為mvp出來有一段時間了,但是還沒怎麼了解過,所以週末看了看,並且敲了幾個demo,感覺有點心得了,就淺談一下自己的理解,不正確的地方請及時指出,謝謝! MVC模式: 邏輯:View通知Con
Android開發:淺談MVP模式應用與記憶體洩漏
最近博主開始在專案中實踐MVP模式,卻意外發現記憶體洩漏比較嚴重,但卻很少人談到這個問題,促使了本文的釋出,本文假設讀者已瞭解MVP架構。 MVP簡介 M-Modle,資料,邏輯操作層,資料獲取,資料持久化儲存。比如網路操作,資料庫操作 V-Vie
JSP學習心得-程式設計師技術淺談
下面是本人在學習JSP時的一些心得,特此奉獻出來以供大家分享。 一、JSP工作原理 在一個JSP檔案第一次被請求時,JSP引擎把該JSP檔案轉換成為一個servlet。而這個引擎本身也是一個servlet,在JSWDK或WEBLOGIC中,它就是JspServlet。
Android 瀏覽器核心淺談
目前,移動裝置瀏覽器上常用的核心有Webkit,Blink,Trident,Gecko等,其中iPhone和iPad等蘋果iOS平臺主要是WebKit,Android 4.4之前的android系統瀏覽器核心是WebKit,Android4.4系統瀏覽器切換到了Chrom
Android dropbox日誌淺談
Android4.4.2 Android dropbox提供了一種儲存日誌的機制,支援將核心、Native、Java多種日誌儲存在"/data/system/dropbox"目錄中。 兩個主要的類是DropBoxManager和IDropBoxManagerService
[Java][Android][Process] Process 創建+控制+分析 經驗淺談
send 實現 亦或 想要 unable github stringbu data- 滿了 不管是Android亦或者Java中或多或少須要調用底層的一些命令。運行一些參數; 此時我們須要用到Java的Process來創建一個子進程。之所以是子進程是由於此進程依賴於發起
淺談非法外聯檢測技術的演變
非法外聯 違規外聯 手機外聯 usb共享 無線熱點 電話撥號 針對隔離內網,非法外聯因其危害巨大,一直都是網絡邊界完整性防護的重中之重。早期非法外聯主要是指以電話撥號為主的私自連接互聯網的行為,早期電話撥號還是非常方便的,如163撥號,263撥號等,只要有電話線,就可以隨時撥號上網,缺
【轉】淺談分布式服務協調技術 Zookeeper
客戶 內存數據 訂閱 數據開發 watcher database 所有 ren info 非常好介紹Zookeeper的文章, Google的三篇論文影響了很多很多人,也影響了很多很多系統。這三篇論文一直是分布式領域傳閱的經典。根據MapReduce,於是
淺談360全景技術對會展的影響及應用
360全景 信息化的時代,一日千變,一個新的技術出現也許在幾秒內就能發生變化。這就是當今的信息速度。近年來360全景技術在中國廣泛運用,且在不斷的發展中。就360全景制作技術這一塊來說,360全景產業在國內外已取得了一定的收獲盈利模式也出現了多樣化,使得360全景產業呈現出欣欣向榮的景象。 會
淺談車牌識別技術的應用
車牌識別技術的應用由來已久,車牌識別增加了車輛管理識別的速度,減少了擁堵,提高了大家的出行舒適度。對於在OCR識別技術領域有著十多年研發經驗的廈門雲脈來說,如何提高車牌識別的準確率,實現更精確的識別更是市場所需。 所以,雲脈自主研發推出的車牌識別技術,基於成熟的OCR技術,以計算機視覺處理、
淺談Nginx服務器的安裝,升級、配置、LNMP平臺搭建、nginx+fastcgi、nginx高級技術-地址重寫及優化
perl 新的 大文件 文件的 add 並發連接數 文件配置 redirect ntp Nginx服務器:是俄羅斯人編寫的十分輕量級的HTTP服務器,是一個高性能的HTTP和反向代理服務器,同時也是一個IMAP/POP3/SMTP代理服務器 一、安裝Nginx軟件: 準備工
淺談Android中的組播(多播)
-1 ip協議 strong 多個 接受 端口 ui線程 nbsp 數據 組播使用UDP對一定範圍內的地址發送相同的一組Packet,即一次可以向多個接受者發出信息,其與單播的主要區別是地址的形式。IP協議分配了一定範圍的地址空間給多播(多播只能使用這個範圍內