之前,在项目经常运用annotation这个注解框架来方便自己的开发,开发非常快。
今天闲来无事,回顾下。Android的注解简单来说就是通过java的反射机制来完成。
那么,我们直接看代码吧
我们先定义一个 BindId的注解
package com.example.boom.annotationproject.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Boom on 2016/11/21.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BindId {
int value() default 0;
}
在定义一个OnClick的注解
package com.example.boom.annotationproject.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Boom on 2016/11/21.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OnClick {
int value() default 0;
}
其中,我们看到的 @Documented @Retention @Target 都是java自带的,而@interface BindId 即@BindId就是我们自定义的注解。总的来说就是用java自带的那些小单元注解构建我们自定义的注解。这是我的个人看法。
那光有定义肯定不行,我们还需要具体。
类 MyAnnotation
package com.example.boom.annotationproject.annotation;
import android.app.Activity;
import android.view.View;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by Boom on 2016/11/21.
*/
public class MyAnnotation {
public static void init(Activity activity){
setBindIdWithViewAnnotation(activity);
getOnClick(activity);
}
private static void setBindIdWithViewAnnotation(Activity activity){
Class clazz=activity.getClass();
Field [] fields=clazz.getDeclaredFields();
for(Field field : fields){
BindId bindId=field.getAnnotation(BindId.class);
if (bindId!=null){
int Id=bindId.value();
try {
field.setAccessible(true);
field.set(activity,activity.findViewById(Id));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
private static void getOnClick(final Activity activity){
Class clazz=activity.getClass();
Method [] methods =clazz.getDeclaredMethods();
for(final Method method : methods){
OnClick onclick =method.getAnnotation(OnClick.class);
if (onclick!=null && onclick.value()!=0){
View v= activity.findViewById(onclick.value());
if (v==null){
return;
}
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
method.setAccessible(true);
method.invoke(activity,v);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
}
}
}
那怎么用呢?
package com.example.boom.annotationproject;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.example.boom.annotationproject.annotation.BindId;
import com.example.boom.annotationproject.annotation.OnClick;
import com.example.boom.annotationproject.annotation.MyAnnotation;
public class MainActivity extends Activity {
@BindId(R.id.tv)
TextView tv;
@OnClick(R.id.tv)
void show(View v){
Toast.makeText(this, "自定义注解成功", Toast.LENGTH_SHORT).show();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyAnnotation.init(this);
tv.setText("自定义注解");
}
}
Class clazz=activity.getClass(); //获取类对象
Field [] fields=clazz.getDeclaredFields(); //获取类中的所有属性
Method [] methods =clazz.getDeclaredMethods(); //获取类中的所有方法
BindId bindId=field.getAnnotation(BindId.class);//找到对应的注解
OnClick onclick =method.getAnnotation(OnClick.class);//找到对应的注解
那么他们是怎么找的呢?
@Target(ElementType.FIELD) //目标是属性
@Target(ElementType.METHOD) //目标是方法
那for循环有什么用?
循环遍历类中的所有属性或者方法
我们再来看看,他们为什么这么写?
field.set(activity,activity.findViewById(Id));
使用时:
@BindId(R.id.tv) TextView tv;
method.invoke(activity,v);
使用时:
show(View v)
第二个参数都是回传的。
其中,我们需要注意的是:
method.setAccessible(true); //如果不写这句话并且show()方法不设置为 public会报 IllegalAccessException的错 method.invoke(activity,v); //如果invoke方法的第二个参数不写,使用的时候show()就不用定义,简而言之就是二个参数是回传的。
我的github项目下载地址:https://github.com/BoomGit/AnnotationProject.git