1.注解的定义

@Target(ElementType ,TYPE)
@Retention(RetentionPolicy , SOURCE)
public @interface Briana{
    String value() default "XXX";
}

元注解:注解上的注解

Target:指明能注解的地方

Retention:注解存活的阶段(SOURCE源码,CLASS字节码,RUNTIME运行时)

2.反射

运行时:反射基于class

3.反射与注解结合

Field:获得自己+父类的成员(不包括private,只能是public)

DecleredFile:只能获得自己的成员(不包括父类,所有的作用域)

4.自定义注解的实现

① 模仿butterknife的@BindView注解实现findViewById。

新建一个注解,把它命名为InjectView。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {
    @IdRes int value();//添加一个语法检查,只能是id
}

新建一个AnnotationUtils工具类,来实现这个注解。

public class AnnotationUtils {

    public static void init(Activity activity) {
        InjectView(activity);
    }
    
    public static void InjectView(Activity activity) {
        Class<? extends Activity> cla = activity.getClass();
        Field[] fields = cla.getDeclaredFields();//获取这个类所有的成员
        for (Field field : fields) {
            //判断属性是否被InjectView注释声明
            if (field.isAnnotationPresent(InjectView.class)) {
                InjectView injectView = field.getAnnotation(InjectView.class);
                int id = injectView.value();//这个value就是传进来的R.id.XXX
                View view = activity.findViewById(id);
                //反射设置
                field.setAccessible(true);//设置访问权限,允许操作private的属性
                try {
                    field.set(activity, view);//反射赋值
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

以上,这个自定义注解就已经完成了,接下来使用这个注解@InjectView试试效果。

在activity_main.xml创建一个id为tv1的TextView,然后在MainActivity里面修改如下:

@InjectView(R.id.tv1)
TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    AnnotationUtils.init(this);
    tv.setText("使用注解绑定组件");
}

点击运行,可以看到TextView显示为 “使用注解绑定组件”。

是不是很简单?那么我们来尝试一下点击事件绑定。

② 实现butterknife的@OnClick,实现按钮的点击事件绑定

新建一个注解,命名为@OnClick。

@Target(ElementType.METHOD)//与@InjectView不一样,这个注解是注释在方法上的
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
    @IdRes int value();
}

接下来,继续在AnnotationUtils类中编写方法来实现@OnClick注解。

public class AnnotationUtils {

    public static void init(Activity activity) {
        InjectView(activity);
        OnClick(activity);//别忘了调用这个方法
    }
    public static void OnClick(final Activity activity) {
        Class<? extends Activity> cla = activity.getClass();
        Method[] methods = cla.getDeclaredMethods();
        for (final Method method : methods) {
            if (method.isAnnotationPresent(OnClick.class)) {
                OnClick onClick = method.getAnnotation(OnClick.class);
                int id = onClick.value();
                View view = activity.findViewById(id);
                view.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View view) {
                        method.setAccessible(true);
                        try {
                            method.invoke(activity, view);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    }
}

以上,@OnClick就完成了。

现在来测试一下,新建一个SecondActivity, 在activity_main.xml新建一个Button。想要实现的功能是,点击button,实现从MainActivity跳转到SeconActivity。

修改MainActivity的代码如下:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    @InjectView(R.id.tv1)
    TextView tv;
    @InjectView(R.id.button)
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        AnnotationUtils.init(this);
        tv.setText("使用注解绑定组件");
    }

    @OnClick(R.id.button)
    public void onClick(View view) {
        Intent intent = new Intent(this, SecondActivity.class);
        startActivity(intent);
    }
}

运行一下,康康效果~

android 自定义数据解析 android自定义注解_User

再来个例子吧~

③ 写一个@GetBean注解,实现activity跳转过程中参数的接收。

首先,我们先新建一个User类,通过Intent把user对象从MainActivity传递到SecondActivity中,再在SecondActivity中使用@GetExtra注解来自动获取。

我们让User类实现Parcelable接口。

public class User implements Parcelable {
    String name;
    int age;
    String gender;

    public User() {
    }

    public User(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    protected User(Parcel in) {
        name = in.readString();
        age = in.readInt();
        gender = in.readString();
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(name);
        parcel.writeInt(age);
        parcel.writeString(gender);
    }
}

其次,创建一个名为GetBean的注解。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GetExtra {
    String value();
}

接下来,在工具类中编写这个注解@GetBean的具体实现。

public class AnnotationUtils {
    public static void init(Activity activity) {
        InjectView(activity);
        OnClick(activity);
        GetBean(activity);
    }
    public static void GetBean(Activity activity) {
        Class<? extends Activity> cla = activity.getClass();
        Field[] fields = cla.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(GetBean.class)) {
                GetBean getExtra = field.getAnnotation(GetBean.class);
                String key = getExtra.value();
                User user = activity.getIntent().getParcelableExtra(key);
                field.setAccessible(true);
                try {
                    field.set(activity, user);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

以上,@GetBean已经写好了,接下来测试一下效果。
在MainActivity.java里面,修改onClick方法如下:

@OnClick(R.id.button)
public void onClick(View view) {
    User user = new User("briana",21,"女");
    Intent intent = new Intent(this, SecondActivity.class);
    intent.putExtra("user",user);
    startActivity(intent);
}

在SecondActivity.java文件里面修改如下:

public class SecondActivity extends AppCompatActivity {
    @GetBean("user")
    User user;
    @InjectView(R.id.tv1)
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        AnnotationUtils.init(this);
        textView.setText("姓名:"+user.getName()+'\n'+"年龄:"+user.getAge()+'\n'+"性别:"+user.getGender());
    }
}

看看效果:

android 自定义数据解析 android自定义注解_android_02