目錄:html
一、基礎知識java
三、總結github
本文是關於ButterKnife的移植的第一篇:api
先介紹基礎知識,理解apt是什麼,最終輸出一個乞丐版BufferKnife注入工具。數組
這是讀懂BufferKnife源碼的基礎。app
第二篇佔坑:具體講解BufferKnife的移植。框架
基礎知識
apt技術的實際應用:
-
Android Databinding綁定viewide
-
ButterKnife綁定view工具
-
Dagger2注入變量
-
ARouter生成路由表
真的好多,很重要。apt就是生產力工具!
什麼是apt?
通俗講:apt就是javac對外開放的一個插件,使javac在編譯期間獲取註解(Annotation),並作出相應的處理(多數都是生成一些java代碼)。
從上圖能夠看出apt處理的是 java源文件 ,在編譯期介入。
與之對比的是asm之類的工具,處理的是字節碼文件,在編譯後期介入。
apt與javac的約定
apt與javac約定在META-INF/services/javax.annotation.processing.Processor
文件中註冊apt插件。這樣apt就參與到javac的編譯過程當中了。
寫一個乞丐版BufferKnife
不想看文字,直接看源碼,點擊 https://gitee.com/andych008/aptDemo
初始代碼fork自 https://github.com/LiMubai2017/aptDemo ,先對做者表示感謝。
乞丐版BufferKnife做爲一款view注入工具,主要乾了3件事,
- 解析註解
- 處理註解(生成模板類文件)
- 經過模板類注入view對象
第0步:準備工做
先定義註解BindView
,被@BindView
標記的變量會被注入。
通常註解都定義在一個單獨的module(如取名apt-annotation),由於它會被apt-compiler和apt-api都依賴,屬於公共代碼。
apt-compiler是apt的主要代碼所在,完成註解的解析、模板文件的生成。
apt-api則是對外的工具類,供用戶使用,完成注入操做。
app是demo,其中定義了
@BindView(value = ResourceTable.Id_text_helloworld) public Text testTextView;
第一步:解析註解
在apt-compiler中定義類BindViewProcessor
繼承javax.annotation.processing.AbstractProcessor
,實現其中的getSupportedAnnotationTypes()
該方法註冊要解析的註解。
第二步:處理註解(生成模板文件)
在BindViewProcessor
中實現process()
方法,處理註解。
先理解javax.lang.model.element.Element
和javax.lang.model.type.TypeMirror
,參考這裏 有詳細的解釋。
簡單講:
Element是描述java語言元素的類,好比包、類、變量、參數等。
TypeMirror是描述Element類型的類,好比各類基本類型、數組、類等。
很繞,只有多用才能真正理解。好比:demo中testTextView
就是VariableElement元素類型
TypeElement enclosingElement = (TypeElement) variableElement.getEnclosingElement();//獲取表明MainAbility的TypeElement String field = variableElement.getSimpleName().toString();//testTextView TypeMirror typeMirror = variableElement.asType();//ohos.agp.components.Text
經過log()
方法,可使用Messager
打日誌,驗證咱們的理解。
log(String.format("element : (%s) %s ", element.getKind(), element)); log(String.format("bind : (%s) %s <--> id = %d", typeMirror, field, id)); 輸出日誌: 注: element : (FIELD) testTextView 注: bind : (ohos.agp.components.Text) testTextView <--> id = 16777222
generateCodeByPoet()
方法中,使用javapoet生成模板代碼MainAbility$$Autobind.java
(文件路徑app/build/generated/source/annotation/debug/com/example/apt_demo/MainAbility$$Autobind.java
)
關於javapoet的使用,直接看官方文檔吧:https://github.com/square/javapoet
解釋一下下面這段代碼,讓你們對javapoet有一直觀的認識
MethodSpec.Builder injectMethod = MethodSpec.methodBuilder("inject")//生成一個方法,方法名是inject .addAnnotation(Override.class)//給方法加上"Override.class"註解 .addModifiers(Modifier.PUBLIC)//給方法加上訪問控制符 .addParameter(Object.class, "target")//給方法加上參數 .addStatement("$T substitute = ($T)target", className, className);//在方法體內定義一條語名
上面的代碼生成下面的代碼(我用java代碼生成java代碼,這就是javapoet乾的事情):
@Override public void inject(Object target) { MainAbility substitute = (MainAbility)target; }
看完上面這一坨,你若是以爲難。請用JavaWriter
生成java文件。你就會以爲javapoet真香。
第三步:經過模板類注入view對象
在apt-api中,咱們定義一個AutoBind.java
類封裝對模板類MainAbility$$Autobind.java
的操做。
按照模板類的命名規則xxx$$Autobind
,經過反射實例化出MainAbility$$Autobind.java
,調用 其中的inject方法,完成view的注入。
總結
apt只是一個工具,在這套工具框架下,怎麼處理註解纔是難點。
BufferKnife和咱們的「乞丐版BufferKnife」本質上沒有區別。除了注入view,還支持事件綁定、增量編譯。
做者:沒用的喵叔
想了解更多內容,請訪問51CTO和華爲合做共建的鴻蒙社區:https://harmonyos.51cto.com