简单的自定义注解

注解是什么?

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释;

元注解一共有四种: 
@Retention,@Target,@Inherited,@Documented

个人理解元注解就是注解之上还有注解

为什么要使用注解?

每当你创建描述符性质的类和接口的时,一旦其中包含重复性工作,就可以考虑简化与自动化该过程。
如果你想把某个方法声明为服务,那么使用Annotation会更好一些,因为这种情况下需要注解和方法紧密耦合起来。

注解的实现

 

最早使用ButterKnife(俗称剃须刀),最喜欢的就是view的绑定写法,简单明了如下

@BindView(R.id.test_btn)
Button btn ;

@BindView(R.id.test_txt)
TextView mTextView;

@Retention 

这个枚举决定了Retention注解应该如何去保持,也可理解为Rentention 搭配 RententionPolicy使用。RetentionPolicy有3个值:CLASS  RUNTIME   SOURCE
按生命周期来划分可分为3类:
1、RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;
2、RetentionPolicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;
3、RetentionPolicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在; 

@Target 提供不同的类型设置不同的属性

ElementType.ANNOTATION_TYPE 可以给一个注解进行注解

ElementType.CONSTRUCTOR 可以给构造方法进行注解

ElementType.FIELD 可以给属性进行注解

ElementType.LOCAL_VARIABLE 可以给局部变量进行注解

ElementType.METHOD 可以给方法进行注解

ElementType.PACKAGE 可以给一个包进行注解

ElementType.PARAMETER 可以给一个方法内的参数进行注解

ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

现在咋们本地自定义一个类似@BindView的注解

@Retention(RetentionPolicy.RUNTIME)  //咋们需要使用并生成class文件的
@Target(ElementType.FIELD)     //表示当前的注解是给属性来使用
public @interface BindView {
   int value();    //int 的属性值
}

添加一个点击事件的注解

@Retention(RetentionPolicy.RUNTIME)  //咋们需要使用并生成class文件的
@Target(ElementType.METHOD)  //说明当前的注解是提供给方法使用的
public @interface OnClick {

   int[] value();  //数组
}

生成完注解,看看注解该如何使用

public class Main extends Activity {
    public static final String cTAG = "MainTest";
    Handler mHandler;
    int count = 5;

    @BindView(R.id.test_btn)
    Button btn ;

    @BindView(R.id.test_txt)
    TextView mTextView;

   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        ButterKnifeProcess.bind(this);  //注解需要初始化才能使用,就像ButterKnife.bind(this)一样
      
    }
    /**
     * 绑定点击事件
     */
    @OnClick({R.id.test_btn})
    public void aaa(View view) {
        mTextView.setText("註解");
    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/test_txt"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="hello" />

    <Button
        android:id="@+id/test_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

注解的具体实现

public class ButterKnifeProcess {
/**
 * 绑定Activity
 */
public static void bind(final Activity activity) {
Class annotationParent = activity.getClass();   //获取当前的class
Field[] fields = annotationParent.getDeclaredFields(); //返回一个数组,其中包含所有声明字段的对象
Method[] methods = annotationParent.getDeclaredMethods();//返回一个数组,其中包含所有声明的方法
for (final Method method : methods) { //遍历方法
   OnClick clickMethod = method.getAnnotation(OnClick.class);  //通过注解获取当前点击的方法
   if (clickMethod != null && clickMethod.value().length != 0) {
      for (int id : clickMethod.value()) {   
         final View view = activity.findViewById(id);  //获取当前的VIew
         view.setOnClickListener(new View.OnClickListener() { //设置点击事件
            @Override
            public void onClick(View v) {
               try {
                  method.invoke(activity, view);  //反射该方法
               } catch (IllegalAccessException e) {
                  e.printStackTrace();
               } catch (InvocationTargetException e) {
                  e.printStackTrace();
               }
            }
         });
      }
   }
}
try {
   for (final Field field : fields) { //遍历当前类所有的对象
      BindView bindView = field.getAnnotation(BindView.class);   //获取bindview对象
      if (bindView != null) {
         View view = activity.findViewById(bindView.value());  //在这里设置activity.findViewById
         field.setAccessible(true);  //启用访问安全检查的开关
         field.set(activity, view);
      }
   }
} catch (IllegalAccessException e) {
   e.printStackTrace();
}

}

}

总结

写法简单明了,方便使用,但是一直遍历反射,比较耗性能。而ButterKnife 整个过程是在项目编译阶段完成,相比之下这种在运行时通过反射的方式就不建议使用了,但是可以理解注解的使用方式,方便以后对应第三方插件注解的理解

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万子开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值