自定义注解

一 案例:

这篇文章将简单介绍下自定义注解:自定义ButterKnife,用注解实现下View的findViewById和onClick事件;
自定义注解一般分为两步:第一步 声明注解,第二步 解析注解。

1 自定义注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyBindView {
    int value() default -1 ;
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

2 自定义注解解析器

import android.app.Activity;
import android.view.View;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyButterKnife {
    public static void init(final Activity activity){
        Class<?> clz = activity.getClass();
        Field[] fields = clz.getDeclaredFields();
        Method[] methods = clz.getDeclaredMethods();
		
		//findViewById
        for(Field field : fields){
            if (field.isAnnotationPresent(MyBindView.class)){
                MyBindView myBindView = field.getAnnotation(MyBindView.class);
                if (myBindView != null){
                    try {
                        field.set(activity, activity.findViewById(myBindView.value()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

		//onClick
        for (final Method method : methods){
            if (method.isAnnotationPresent(MyOnClick.class)){
                MyOnClick onClick = method.getAnnotation(MyOnClick.class);
                if (onClick != null && onClick.value().length > 0){
                    for(int id : onClick.value()){
                        View view = activity.findViewById(id);
                        if (view != null){
                            view.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    try {
                                        method.invoke(activity, view);
                                    } catch (IllegalAccessException e) {
                                        e.printStackTrace();
                                    } catch (InvocationTargetException e) {
                                        e.printStackTrace();
                                    }
                                }
                            });
                        }
                    }

                }
            }
        }
    }
}

这里运用了反射来操作,调用bind方法后,先用cls.getDeclaredFields();获取所有的全局变量,然后再对每个变量用field.getAnnotation(BindView.class);来获取这个变量上面的注解,如果存在的话 int ids = bindView.value(); 来获取我们传入的资源,最后调用findViewById:

field.set(activity, activity.findViewById(myBindView.value()));

3 使用

public class TestActivity extends Activity {

    @MyBindView(R.id.tv)
    TextView textView;

    @MyOnClick(R.id.tv)
    void tvClick(View view){
        Toast.makeText(this, "点击了", Toast.LENGTH_LONG).show();
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        MyButterKnife.init(this);

        textView.setText("111111");
    }
}

4 类结构
在这里插入图片描述

注意:
使用注解的的类要和声明注解类在一个包下,否则会报这种错误:

Class java.lang.Class<MyAnnotation.MyButterKnife> cannot access field android.widget.TextView zzf.com.testkotlin2.TestActivity.textView of class java.lang.Class<zzf.com.testkotlin2.TestActivity>

二 注解

1 什么是注解

对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
  Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。

2 注解的原理:

注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。

3 注解的作用

简化代码,提高开发效率。
注意:肯定是能提高代码开发效率,并不一定能提供程序运行效率。

三 元注解

元注解是用来定义其他注解的注解(在自定义注解的时候,需要使用到元注解来定义我们的注解)。java.lang.annotation提供了四种元注解:@Retention、 @Target、@Inherited、@Documented。

元注解是用来修饰注解的注解。在自定义注解的时候我们肯定都是要用到元注解的。因为我们需要定义我们注解的是方法还是变量,注解的存活时间等等。

在这里插入图片描述
1 @Target
@Target元注解用来表明我们注解可以出现的地方,参数是一个ElementType类型的数组,所以@Target可以设置注解同时出现在多个地方。比如既可以出现来类的前面也可以出现在变量的前面。
@Target元注解ElementType枚举(用来指定注解可以出现的地方):
在这里插入图片描述
2 @Retention
@Retention表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)。参数是RetentionPolicy枚举对象。
RetentionPolicy的枚举类型有(默认值为CLASS.):
在这里插入图片描述
3 @Document
@Document表明我们标记的注解可以被javadoc此类的工具文档化。

4 @Inherited
@Inherited表明我们标记的注解是被继承的。比如,如果一个父类使用了@Inherited修饰的注解,则允许子类继承该父类的注解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值