Android笔记-注解
一、注解
1.1注解分类
注解分类.png1.2、示例
1、定义注解
public @interface Swordsman {
String name() default "张三";//default设置默认值
int age() default 23;
}
2、使用注解
@Swordsman(name = "李四", age = 18)
public class AnnotationTest {
}
3、定义运行时注解
@Retention(RetentionPolicy.RUNTIME)
public @interface Swordsman {
String name() default "张三";//default设置默认值
int age() default 23;
}
4、定义编译时注解
@Retention(RetentionPolicy.CLASS)
public @interface Swordsman {
String name() default "张三";//default设置默认值
int age() default 23;
}
@Retention来设定注解的保留策略,这 3 个策略的生命周期长度为 SOURCE <CLASS<RUNTIME。
1.3注解处理器
1.运行时注解处理器
1.1定义运行时注解
// 上面必须要有两个标识
@Target(ElementType.FIELD) // Target 放在哪里?哪里可以使用 FIELD 属性 TYPE 类上 METHOD 属性
// 什么时候起作用 ,RUNTIME 运行时(程序运行中) CLASS 代表的是编译时(打包的时候) SOURCE 编程阶段
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewById {// @interface 代表注解
int value();
}
1.2定义注解处理的工具类
public class ViewUtils {
public static void inject(Activity activity) {
// 1.获取所有的属性
Field[] fields = activity.getClass().getDeclaredFields();
// 2.过滤关于 ViewById 属性
for (Field field : fields) {
ViewById viewById = field.getAnnotation(ViewById.class);
if (viewById != null) {
// 3.findViewById
View view = activity.findViewById(viewById.value());
field.setAccessible(true);//设置权限
// 4.反射注入
try {
// activity 属性所在类,view 代表的是属性的值
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
1.3使用
public class MainActivity extends BaseActivity {
@ViewById(R.id.tv)
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewUtils.inject(this);
tv.setText("ViewById");
}
}
2.编译时注解处理器
ButterKnife用到了编译时注解,用apt生成代码,生成的类名×××Activity_ViewBinding,初始化时使用到了1次反射
1、定义注解
新建一个Java Library来专门存放注解,名为annotations
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.FIELD)
public @interface BindView {
int value() default 1;
}
2、编写注解处理器
再新建一个Java Library来存放注解处理器,这个Library名为processor。配置
processor库的build.gradle:
dependencies {
...
compile project(':annotations ')
}
注解处理器ClassProcessor,它继承AbstractProcessor
public class ButterKnifeProcessor extends AbstractProcessor {
//被注解处理工具调用
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
}
// 1. 指定处理的版本
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
// 2. 给到需要处理的注解
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> types = new LinkedHashSet<>();
for (Class<? extends Annotation> annotation : getSupportedAnnotations()) {
types.add(annotation.getCanonicalName());
}
return types;
}
//必须指定的方法,指定这个注解处理器是注册给哪个注解的
//返回值是一个字符串的集合,包含本处理器想要处理的注解类型的合法全称
private Set<Class<? extends Annotation>> getSupportedAnnotations() {
Set<Class<? extends Annotation>> annotations = new LinkedHashSet<>();
// 需要解析的自定义注解 BindView OnClick
annotations.add(BindView.class.getCanonicalName);
return annotations;
}
//process:相当于每个处理器的主函数main(),在这里写你的扫描、评估和处理注解的代码,以及生
成Java文件
@Override
public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
//提供注解处理器的方式报告错误消息,警告,等通知
Messager messager = processingEnv.getMessager();
for (Element element : roundEnvironment.getElementsAnnotatedWith(BindView.class)) {
//判断当前注解是否为成员变量
if (element.getKind() == ElementKind.FIELD) {
//打印出注解修饰的成员变量名称
messager.printMessage(Diagnostic.Kind.NOTE, "printMessage:" + element.toString());
}
}
return true;
}
3、注册注解处理器
使用服务文件来注册,简便方法使用Google开源的AutoService用来生成生成META-INF/services/javax.annotation.processing.Processor文件
在File→Project Structure 搜索“auto-service”查找该库并添加
使用
@AutoService(Processor.class)
public class ButterKnifeProcessor extends AbstractProcessor {
...
}
4、应用注解
在主工程项目(app)中引用注解
dependencies {
...
compile project(':annotations ')
compile project(':processor')
}
MainActivity中应用注解
@BindView(value = R.id.tv)
TextView tv_text;
最后,先Clean Project再Make Project
编译时会打印出@BindView注解修饰的成员变量名:tv_text
5、使用android-apt插件
两个作用:
• 仅仅在编译时期去依赖注解处理器所在的函数库并进行工作,但不会打包到APK中。
• 为注解处理器生成的代码设置好路径,以便Android Studio能够找到它。
使用
整个工程(Progect)的 build.gradle 中添加
dependencies {
...
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
主工程项目(app)的 build.gradle 中以apt的方式引入注解处理器processor
...
apply plugin: 'com.neenbedankt.android-apt'
...
dependencies {
...
//compile project(':processor')
apt project(':processor')
}