【Android】如何實現ButterKnife

如何實現ButterKnife

ButterKnife的原理簡述java

示例代碼ButterKnifeProcedureandroid

Pluggable Annotation Processing

註解處理器
Java5 中叫APT(Annotation Processing Tool),在Java6開始,規範化爲 Pluggable Annotation Processing。git

第一步(收集信息)

找到全部被註解的屬性或者方法,將全部的信息收集到對應的「類數據集」中。github

第二步(生成源文件)

根據每個「類數據集」,生成對應的java源文件。因爲這些文件並非在運行時生成的,所以也無需動態編譯,註解處理器運行完成以後,
編譯器會處理全部的編譯流程。緩存

第三步(動態注入)

運行時動態注入,即用戶常規調用的 ButterKnife.bind(activity)app

這一步爲了不蹩腳的調用,使用了運行時反射,可是做者對每個類進行了緩存,所以,不會對執行效率產生多大影響。ide

在最新的 ButterKnife 源碼(2015.06.08)中,ButterKnife已經重構了部分方法:工具

ButterKnife#inject -> ButterKnife#bind命令行

@InjectView -> @FindViewcode

等等,具體變化能夠去看官方文檔,本文檔後續代碼使用最新版本代碼演示

極簡實現演示

演示代碼說明

  1. 示例代碼由 ButterKnife 簡化而來,部分定義和實現有刪改,只能綁定 Activity 中的 View 字段
  2. 爲了不引入Android平臺,可是又須要更直觀,因此mock了android的兩個類,ActivityView
  3. 爲了不使用 Pluggable Annotation Processing 過程當中的jar包要求,以及波及沒必要要的java文件,請使用命令行運行演示,直接運行 ./run.sh 便可查看結果
  4. 保證 CLASSPATH 中含有tools.jar

第一步(收集信息)

  1. 在每個類中找到全部被 FindView 註解的字段
  2. 每個須要綁定的字段信息都保存爲一個 FieldViewBinding 對象,好比:

    @FindView(100)
     View vView1;
     獲得:
     new FieldViewBinding(vView1, android.view.View, 100)
  3. 將字段分類,獲取每個類的「類數據集」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 接口,所以,根據 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

相關文章
相關標籤/搜索