平時大家用的注解都是運行時通過反射機(jī)制運行處理|的注解翅睛,本篇文章討論的是編譯時處理的注解力喷,一般用來自動生成代碼的注解例如ButterKnife慷妙;
如果需要使用注解處理器址儒,引用時使用代碼如下(以butterknife舉例):
implementation 'com.jakewharton:butterknife:8.5.1'
//引用注解處理器芹枷,在編譯是自動生成相關(guān)代碼
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'
使用ButterKnife的主代碼
public class ScrollingActivity extends AppCompatActivity {
private static final String TAG = "ScrollingActivity";
@BindView(R.id.btn_bk)
Button mBtnBk;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scrolling);
ButterKnife.bind(this);
}
private void annotationStartActivity() {
RouterService routerService = new Router(this).create(RouterService.class);
User user = new User("張三來了", 300);
routerService.startLibraryActivity("xiaoma", user);
}
@OnClick(R.id.btn_bk)
public void onClick(View v) {
switch (v.getId()) {
default:
break;
case R.id.btn_bk:
annotationStartActivity();
break;
}
}
}
編譯后自動生成了ScrollingActivity_ViewBinding類,而 ButterKnife.bind(this)相當(dāng)于初始化了這個類,如果去掉 ButterKnife.bind(this)莲趣,改成new ScrollingActivity_ViewBinding(this)是跟上面的代碼功能一致的鸳慈;該類代碼如下:
public class ScrollingActivity_ViewBinding implements Unbinder {
private ScrollingActivity target;
private View view2131230756;
@UiThread
public ScrollingActivity_ViewBinding(ScrollingActivity target) {
this(target, target.getWindow().getDecorView());
}
@UiThread
public ScrollingActivity_ViewBinding(final ScrollingActivity target, View source) {
this.target = target;
View view;
view = Utils.findRequiredView(source, R.id.btn_bk, "field 'mBtnBk' and method 'onClick'");
target.mBtnBk = Utils.castView(view, R.id.btn_bk, "field 'mBtnBk'", Button.class);
view2131230756 = view;
view.setOnClickListener(new DebouncingOnClickListener() {
@Override
public void doClick(View p0) {
target.onClick(p0);
}
});
}
@Override
@CallSuper
public void unbind() {
ScrollingActivity target = this.target;
if (target == null) throw new IllegalStateException("Bindings already cleared.");
this.target = null;
target.mBtnBk = null;
view2131230756.setOnClickListener(null);
view2131230756 = null;
}
下面說下注解處理器
- 虛處理器AbstractProcessor
注解處理器的入口就是繼承了AbstractProcessor的繼承類的process方法
@AutoService(Processor.class)
public class InjectProcessor extends AbstractProcessor {
private Types mTypeUtils;
private Filer mFiler;
private Messager mMessages;
private Elements mElementUtils;
@Override
public synchronized void init(ProcessingEnvironment env){
/* Element代表程序的元素,例如包喧伞、類和方法*/
mElementUtils = processingEnv.getElementUtils();
/*處理TypeMirror的工具類走芋,用于取類信息*/
mTypeUtils = processingEnv.getTypeUtils();
/* File可以創(chuàng)建文件*/
mFiler = processingEnv.getFiler();
mMessages = processingEnv.getMessager();
}
@Override
public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) { }
@Override
public Set<String> getSupportedAnnotationTypes() { }
@Override
public SourceVersion getSupportedSourceVersion() { }
}
- init(ProcessingEnvironment env)方法用來提供核心的四個參數(shù)分別是Elements、Types潘鲫、Filer翁逞、Messager
- process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)核心入口
- getSupportedAnnotationTypes() 必須指定這個注解處理器是注冊給那個注解的,注意返回的是一個字符串的集合,也就是改注解處理器處理你指定的注解結(jié)合
- getSupportedSourceVersion() 用來指定你使用的java版本溉仑;建議直接使用SourceVersion.latestSupported()返回
- 注冊你的處理器
怎么把處理器InjectProcessor注冊到j(luò)avac中挖函,通過google提供的auto-service引用到項目中,并且把@AutoService(Processor.class)放到類InjectProcessor 上面就可以
apply plugin: 'java-library'
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.squareup:javapoet:1.8.0'
implementation 'com.google.auto.service:auto-service:1.0-rc5'
implementation project(':processor')
}
sourceCompatibility = "7"
targetCompatibility = "7"
- 拋出問題處理
如果你在process()中拋出一個異常,那么運行注解處理器的JVM將會崩潰(就像其他Java應(yīng)用一樣)浊竟,使用我們注解處理器FactoryProcessor第三方開發(fā)者將會從javac中得到非常難懂的出錯信息怨喘,因為它包含F(xiàn)actoryProcessor的堆棧跟蹤(Stacktace)信息。因此振定,注解處理器就有一個Messager類哲思,它能夠打印非常優(yōu)美的錯誤信息,并且return true,退出處理 - 自動生成代碼,也是注解處理器的關(guān)鍵內(nèi)容吩案,這樣生成的新類就可以直接使用棚赔,建議使用如下引用庫生成java代碼
implementation 'com.squareup:javapoet:1.8.0'
相關(guān)內(nèi)容可以搜索javapoet相關(guān)內(nèi)容
- 分離注解處理器和注解
這樣處理器相關(guān)的代碼就無序引用到項目內(nèi)了,只把對應(yīng)的注解引入就ok
關(guān)于路由和注解的項目地址
參考文章: 注解處理器