注解这东西虽然在jdk1.5就加进来了,但他的存在还是因为使用Afinal框架的view注入才知道的。一直觉得注入特神奇,加了一句就可以把对应view生成了。
下面我们来认识一下注解这个东西
一、注解相关知识
注解相当于一种标记,在javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
1、元注解:作用是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明
@Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
ElementType参数有:
1)CONSTRUCTOR:用于描述构造器
2)FIELD:用于描述域
3)LOCAL_VARIABLE:用于描述局部变量
4)METHOD:用于描述方法
5)PACKAGE:用于描述包
6)PARAMETER:用于描述参数
7)TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention:用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
RetentionPoicy参数有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
@Documented 表明这个注解被javadoc工具记录,默认是不被javadoc注解的. 即声明注解@Documented,则注解类型信息会被生成在文档中
@Inherited指明被注解的类会自动继承,即:注解类中的所有属性与方法会被子类继承
二、自定义注解
语法:public @interface 注解名 {定义体}
注解方法参数要求:
1)只能用public或默认(default)这两个访问权修饰
2)参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.
3)如果只有一个参数成员,最好把参数名称设为"value"
4)注解元素必须有确定的值。可以在定义注解的默认值中指定,或在使用注解时指定。如:String onClick() default "";
代码如下:
定义注解
1 @Target(ElementType.FIELD) 2 @Retention(RetentionPolicy.RUNTIME) 3 @Documented 4 public @interface FindViewByIdAnnotation { 5 6 int id() default 0; 7 String onClick() default ""; 8 9 }
使用注解
1 @FindContentViewAnnotation(R.layout.activity_annotation) 2 public class AnnotationActivity extends Activity { 3 4 @FindViewByIdAnnotation(id = R.id.tvShow, onClick = "onClickShow") 5 private TextView tvShow; 6 7 @FindViewByIdAnnotation(id = R.id.tvHello, onClick = "onClickHello") 8 private TextView tvHello; 9 10 @Override 11 protected void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 FindViewUtil.initView(this); 14 } 15 16 public void onClickShow() { 17 Toast.makeText(getApplicationContext(), "show Mr-Mo", Toast.LENGTH_SHORT).show(); 18 } 19 public void onClickHello() { 20 Toast.makeText(getApplicationContext(), "hello Mr-Mo", Toast.LENGTH_SHORT).show(); 21 } 22 }
三、注解处理器
注解如果不写注解处理器基本相当于注释。所以一般都会写一个注解处理器。FindViewUtil:
1 public class FindViewUtil { 2 3 private FindViewUtil() { 4 } 5 6 public static void initView(Object object) { 7 initContentView(object); 8 initComponentView(object); 9 } 10 11 /** 12 * 初始化setContentView资源布局 13 * 14 * @param object 15 */ 16 private static void initContentView(Object object) { 17 Class clazz = object.getClass(); 18 FindContentViewAnnotation contentView = (FindContentViewAnnotation) clazz.getAnnotation(FindContentViewAnnotation.class); 19 if (contentView != null) { 20 try { 21 int resId = contentView.value(); 22 // activity.setContentView(resId); 23 Method setContentViewMethod = clazz.getMethod("setContentView", int.class); 24 setContentViewMethod.invoke(object, resId); 25 26 } catch (Exception e) { 27 e.printStackTrace(); 28 } 29 } 30 } 31 32 /** 33 * 初始化控件 34 * 35 * @param object 36 */ 37 private static void initComponentView(final Object object) { 38 try { 39 final Class clazz = object.getClass(); 40 Field[] fields = clazz.getDeclaredFields(); 41 for (Field field : fields) { 42 FindViewByIdAnnotation viewByIdAnnotation = field.getAnnotation(FindViewByIdAnnotation.class); 43 if (viewByIdAnnotation != null) { 44 int resId = viewByIdAnnotation.id(); 45 final String onClick = viewByIdAnnotation.onClick(); 46 Object view; 47 if (object instanceof Fragment) { 48 Method getViewMethod = clazz.getMethod("getView"); 49 View rootView = (View) getViewMethod.invoke(object); 50 view = rootView.findViewById(resId); 51 } else { 52 Method findViewByIdMethod = clazz.getMethod("findViewById", int.class); 53 view = findViewByIdMethod.invoke(object, resId); 54 } 55 56 field.setAccessible(true); 57 field.set(object, view); 58 59 if (onClick != null && onClick.trim().length() > 0) { 60 Object objectField = field.get(object); 61 if (objectField instanceof View) { 62 final Method onClickMethod = clazz.getMethod(onClick); 63 View viewItem = (View) objectField; 64 viewItem.setOnClickListener(new View.OnClickListener() { 65 @Override 66 public void onClick(View v) { 67 try { 68 onClickMethod.setAccessible(true); 69 onClickMethod.invoke(object); 70 } catch (Exception e) { 71 e.printStackTrace(); 72 } 73 } 74 }); 75 } 76 } 77 } 78 } 79 } catch (Exception e) { 80 e.printStackTrace(); 81 } 82 } 83 84 }
到此就是自定义注解的全部步骤,以上代码可以完成view注入功能。
本文部分知识总结自:http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
代码下载地址:https://github.com/MrxMo/IOCView