對比 findViewById 繁瑣、Afinal 運行時反射效能差,ButterKnife 採用編譯期注解處理(APT)生成輔助類,零反射、零運行時開銷,僅增加微小編譯時間。
@BindView(R.id.tv) TextView tv;
↓ 編譯期 (javac -processor ButterKnifeProcessor)
生成類:Activity$$ViewBinder
↓ 實現 ViewBinder 介面
bind(Finder, T, Object) 方法體:
tv = finder.findRequiredView(source, 2130968576, "field 'tv'");
target.tv = finder.castView(tv, 2130968576, "field 'tv'");
↓ 運行時
ButterKnife.bind(this) → Activity$$ViewBinder.bind(...)
@Override public void bind(Finder finder, T target, Object source) {
Unbinder unbinder = new Unbinder(target); // 若有 @Unbinder
View view;
view = finder.findRequiredView(source, R.id.tv, "field 'tv'");
target.tv = finder.castView(view, R.id.tv, "field 'tv'");
// ... 其他欄位
target.unbinder = unbinder;
// @BindString/@BindDrawable 等資源注入略
}
@Retention(CLASS) @Target(TYPE)
public @interface BindLayout { @LayoutRes int value(); }
@Override public Set getSupportedAnnotationTypes() {
Set types = new LinkedHashSet<>();
types.add(BindLayout.class.getCanonicalName());
return types;
}
private void parseBindLayout(Element element, Map map, Set erased) {
TypeElement type = (TypeElement) element; // @BindLayout 標註在類上
int layoutId = type.getAnnotation(BindLayout.class).value();
BindingClass bc = getOrCreateTargetClass(map, type);
bc.setContentLayoutId(layoutId); // 存入 BindingClass
}
private MethodSpec createBindMethod() {
MethodSpec.Builder result = MethodSpec.methodBuilder("bind") ...;
if (layoutId != 0) {
result.addStatement("target.setContentView($L)", layoutId); // 插在 view 注入之前
}
// ... 原有 view/unbinder 生成邏輯
return result.build();
}
@BindLayout(R.layout.simple_activity)
public class SimpleActivity extends Activity { ... }
生成代碼自動包含 target.setContentView(2130837504);,徹底告別 setContentView() 样板代碼。
| 框架 | 定位 | 核心機制 | 優勢 |
|---|---|---|---|
| ButterKnife | View/資源注入 | APT 生成 ViewBinder | 輕量、專注、零反射 |
| androidannotations | 全能注入(線程、網絡、View...) | APT 生成子類/輔助類 | 功能豐富、結構清晰 |
| Dagger 2 | 依賴注入框架 | APT 生成工廠/圖 | 編譯期驗證依賴圖、無反射、Google 維護 |
javax.annotation.processing API + JavaPoet 寫出 .java 源文件。@BindLayout、@BindAdapter 等)。解放雙手,讓編譯器幫你寫代碼!