#如何實現ButterKnifejava
ButterKnife的原理簡述android
示例代碼ButterKnifeProceduregit
#Pluggable Annotation Processinggithub
註解處理器 Java5 中叫APT(Annotation Processing Tool),在Java6開始,規範化爲 Pluggable Annotation Processing。緩存
##第一步(收集信息) 找到全部被註解的屬性或者方法,將全部的信息收集到對應的「類數據集」中。app
##第二步(生成源文件) 根據每個「類數據集」,生成對應的java源文件。因爲這些文件並非在運行時生成的,所以也無需動態編譯,註解處理器運行完成以後, 編譯器會處理全部的編譯流程。ide
##第三步(動態注入) 運行時動態注入,即用戶常規調用的 ButterKnife.bind(activity)工具
這一步爲了不蹩腳的調用,使用了運行時反射,可是做者對每個類進行了緩存,所以,不會對執行效率產生多大影響。命令行
###注 在最新的 ButterKnife 源碼(2015.06.08)中,ButterKnife已經重構了部分方法:code
ButterKnife#inject -> ButterKnife#bind
@InjectView -> @FindView
等等,具體變化能夠去看官方文檔,本文檔後續代碼使用最新版本代碼演示。
#極簡實現演示
##演示代碼說明
##第一步(收集信息)
在每個類中找到全部被 FindView 註解的字段
每個須要綁定的字段信息都保存爲一個 FieldViewBinding 對象,好比:
@FindView(100) View vView1; 獲得: new FieldViewBinding(vView1, android.view.View, 100)
將字段分類,獲取每個類的「類數據集」BindingClass,好比, MainActivity 對應的 「類數據集」 以下:
MainActivity: List<FieldViewBinding> fieldViewBindings = new ArrayList<FieldViewBinding>(); fieldViewBindings.add(new FieldViewBinding(vView1, android.view.View, 100)) fieldViewBindings.add(new FieldViewBinding(vView2, android.view.View, 200))
##第二步(生成 Bind 工具類源文件)
爲了便於在反射時容易實例化生成的類,每個生成的類都實現了一個 ActivityBinder<T extends Activity> 接口,所以,根據 MainActivity 「類數據集」生成的文件以下:
package sample; import android.view.View; import android.app.Activity; import butterknife.ButterKnife.ActivityBinder; public class MainActivity$$ViewBinder implements ActivityBinder<sample.MainActivity> { @Override public void bind(sample.MainActivity target) { View view; view = target.findViewById(100); target.vView1 = view; //這裏要求 vView1 的訪問權限爲 package 級別 view = target.findViewById(200); target.vView2 = view; } }
##第三步(動態注入) 咱們在 MainActivity 中調用 ButterKnife#bind,第一件事就是找到對應生成的 Bind 工具類,這裏遵循命名規則(在對應類後增長 $$ViewBinder 後綴),直接使用動態加載並實例化:
Class<?> activityBindingClass = Class.forName(targetClass.getName() + ButterKnifeProcessor.SUFFIX); activityBinder = (ActivityBinder) activityBindingClass.newInstance();
得到相應的 ActivityBinder 以後,使用 ActivityBinder#bind 進行綁定,與手動調用 findViewById 效果相同
##運行
運行:
ButterKnifeProcedure/src$ ./run.sh
結果:
mainActivity.vView1.id = 100 mainActivity.vView2.id = 200
###Android分享 Q羣:315658668