5. 限定注解的使用范围@Target
TYPE: 用于类,接口,枚举但不能是注解
FIELD: 字段上,包括枚举值
METHOD: 方法,不包括构造方法
PARAMETER: 方法的参数
CONSTRUCTOR: 构造方法
LOCAL_VARIABLE: 本地变量或catch语句
ANNOTATION_TYPE: 注解类型(无数据)
PACKAGE: Java包
6. 注解保持性策略RetentionPolicy
1) RUNITIME: 保留在编译的类文件中,并在第一次加载类时读取它;
2) CLASS: 保留在编译后的类文件中,但在运行时忽略它;
3) SOURCE: 按规定使用注解,但并不将它保留在编译后的类文件中;
(1)自定义注解
1) 先定义布局文件注入:
//注解的作用域在类上
@Target(ElementType.TYPE)
//让保持性策略为运行时态,将注解编码到class文件中,让虚拟机读取
@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
int value();//使用时直接@ContentView(R.layout.xxx)指定的R.layout.xxx就是布局文件,会自动注入布局文件
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
2) 布局中控件注入文件
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
}
- 1
- 2
- 3
- 4
- 5
3) 控件的点击响应注入文件
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
int[] value();
}
(2) 使用自定义注解
对一个成员变量使用@BindView注解,并传入一个View Id, ButterKnife就能够找到对应的View,并自动进行转换成所需控件类型。
@Contentview(R.layout.activity_main) public class MainActivity extends AppCompatActivity { @ViewInject(R.id.name_tv) TextView name_tv; @ViewInject(R.id.tu_iv) ImageView tu_iv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewInjectUtils.getutil(this); } //方法名字任意起 @OnClick({R.id.bt,R.id.bt1}) public void ni(View view){ switch (view.getId()) { case R.id.bt: Toast.makeText(MainActivity.this,"你猜",Toast.LENGTH_SHORT).show(); break; case R.id.bt1: Toast.makeText(MainActivity.this,"啥都不会",Toast.LENGTH_SHORT).show(); break; } }
(3) 通过反射机制获取注解参数
1) 布局文件获取
private static void jnectContentView(Activity activity) {
//获取activity的类实例
Class<? extends Activity> clazz = activity.getClass();
//获取到activity的ContentView注解
ContentView contentView = clazz.getAnnotation(ContentView.class);
if (contentView != null) {
//如果activity上面存在这个注解的话,就取出这个注解对应的value值,就是前面设置的布局
int layoutId = contentView.value();
try {
//利用反射调用setContentView方法,完成注入
Method setViewMethod = clazz.getMethod("setContentView", int.class);
setViewMethod.invoke(activity, layoutId);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
2) 控件获取实现
private static void injectView(Activity activity) {
Class<? extends Activity> clazz = activity.getClass();
//获取activity的所有成员变量
Field[] fields = clazz.getDeclaredFields();
//遍历成员变量,获取成员变量上的ViewInject注解
for (Field field : fields) {
//获取字段上面的注解对象,同有则继续下一个字段
ViewInject viewInject = field.getAnnotation(ViewInject.class);
if (viewInject != null) {
//获取ViewInject注解的View的id
int viewId = viewInject.value();
//获取控件
View view = activity.findViewById(viewId);
try {
//设置field为可访问,就算私有的也能访问到
field.setAccessible(true);
//将该控件设置给field对象
field.set(activity, view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
3)控件点击响应
//点击事件 public static void injectEvent(final Activity activity) { //获取所有的方法 Method[] methods = activity.getClass().getDeclaredMethods(); for (final Method method : methods) { if (method!=null&&methods.length>0){ //暴力反射 method.setAccessible(true); //OnClick为注解的类名 OnClick click = method.getAnnotation(OnClick.class); if (click!=null){ int[] value = click.value(); for (int i : value) { //获取每一个view final View viewById = activity.findViewById(i); //给每个view都设置点击事件 viewById.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { try { method.invoke(activity,viewById); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }); } } } } }
参考:http://blog.csdn.net/smileiam/article/details/72771634 文件获取和控件获取
https://www.cnblogs.com/YukiKun/p/5143937.html 点击事件
http://blog.csdn.net/tongseng/article/details/72859162