注解介绍 + 实现自定义ButterKnife效果

174 阅读2分钟

注解介绍

Java中的注解非常的多,在Android中最主要的还是这2个注解,@Target和@Retention

@Target

@Target是什么?

定义了在哪些地方可以使用注解,比如:类,属性,方法,参数,构造方法,局部变量,包声明等。

@Target注解有几种值?

1、TYPE:类、接口、枚举

2、FIELD:在属性上声明

3、METHOD:在方法上声明

4、PARAMETER:在参数上声明

5、CONSTRUCTOR:在构造上声明

6、ANNOTATION_TYPE:注解类型声明

7、LOCAL_VARIABLE:局部变量声明

8、PACKAGE:包声明

@Retention

@Retention是什么?

定义了注解在哪些阶段可以使用,源码阶段、class阶段、运行时阶段。

@Retention的值有哪些?

1、RetentionPolicy.SOURCE:注解只能存在于源码中。

2、RetentionPolicy.CLASS:注解一直存在于字节码阶段。

3、RetentionPolicy.RUNTIME:注解存在于运行时阶段。

利用注解实现ButterKnife效果

1、定义OnClick注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OnClick {
    int value() default -1;
}

2、定义BindView注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BindView {
    int value() default -1;
}

3、定义ButterKnife类

public class ButterKnife {

    @RequiresApi(api = Build.VERSION_CODES.N)
    public static void bind(final Activity activity) {
        if (activity == null) {
            return;
        }
        try {
            // 获取字节码
            Class clazz = activity.getClass();

            // 遍历所有的方法,获取方法上是否有OnClick的注解,如果有注解,首先通过id找到对应的控件,
            // 然后设置点击事件,然后再通过反射来执行方法。
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                final OnClick onClick = method.getDeclaredAnnotation(OnClick.class);
                if (onClick != null) {
                    final View view = activity.findViewById(onClick.value());
                    // 设置可以访问
                    method.setAccessible(true);
                    // 设置点击事件,然后再通过反射调用方法。
                    view.setOnClickListener(v -> {
                        try {
                            method.invoke(activity, view);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
                }
            }

            // 遍历所有的字段,然后检测是否有BindView注解,如果有注解,那么执行findViewById的操作。
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                BindView bindView = field.getDeclaredAnnotation(BindView.class);
                if (bindView != null) {
                    View view = activity.findViewById(bindView.value());
                    //设置可以访问
                    field.setAccessible(true);
                    // 将控件设置给field对象,这句话很关键
                    field.set(activity, view);
                }
            }

        } catch (Exception e) {

        }
    }
}

4、然后在页面中调用

public class TestActivity extends AppCompatActivity {

    @BindView(R.id.tv)
    TextView tv;

    @RequiresApi(api = Build.VERSION_CODES.N)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test5);

        ButterKnife.bind(this);
        tv.setText("Success");
    }

    @OnClick(R.id.tv)
    public void onClick(View view) {
        Toast.makeText(this, "Success!", Toast.LENGTH_SHORT).show();
    }


}