美文网首页Android开发Android开发经验谈Android技术知识
如何实现自定义Java运行时注解功能

如何实现自定义Java运行时注解功能

作者: 皮球二二 | 来源:发表于2016-06-01 13:07 被阅读2196次

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

    基础知识

    相信大家在Android开发过程中,对注解有一定程度的接触,比如我们在使用EventBus的时候,我们声明

    @Subscribe(threadMode = ThreadMode.MainThread)
    

    来接受通过EventBus发出来的数据,
    还有ButterKnife,我们在使用OnClick添加点击事件或Bind绑定组件的时候,同样也有类似的写法

    @Bind(R.id.index_image)
    @OnClick({R.id.index_layout)
    

    以至于什么@Override、@Deprecated、@SuppressWarnings这就不需要说了。
    我们在写的时候,最大的感触就是:太方便了!!!直接加一个声明就Ok了。你是不是心动了,自己也写几个注解,是不是程序能够更加简洁一些了?先别急,看看注解的结构

    @Retention(CLASS) 
    @Target(FIELD)
    public @interface Bind {  
    /** View ID to which the field will be bound. */  
        int[] value();
    }
    

    其实一点概念都不知道的话,确实看到这个会懵逼。我们一个个来解释一下

    1. Retention 表示在什么级别保留此信息
      SOURCE:源码注解,注解仅存在代码中,注解会被编译器丢弃
      CLASS:编译时注解,注解会在class文件中保留,但会被VM丢弃
      RUNTIME:运行时注解,VM运行期间也会保留该注解,因此可以通过反射来获得该注解
    2. Target 表示作用域,可能的ElementType参数包括:
      CONSTRUCTOR:构造方法声明
      FIELD:字段声明
      LOCAL_VARIABLE:局部变量声明
      METHOD:方法声明
      PACKAGE:包声明
      PARAMETER:参数声明
      TYPE:类,接口或enum声明
    3. Inherited 容许子类继承
    4. Documented 生成javadoc时会包含注解

    实战1---获取注解值

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface MyAnnotation {    
        String value() default "defaultValue";    
        int age();
    }
    

    我们声明了一个运行时的注解,可以作用在类还有方法上,包含2个成员变量,其中value有一个默认值是defaultValue
    来看看如何获取

    @MyAnnotation(age = 10)
    public class AnnotationDemo {    
        @MyAnnotation(value = "Hello", age = 100)    
        public static void main(String[] args) {        
            try {            
                Class class_=Class.forName("com.renyu.demo.AnnotationDemo");            
                Annotation myAnnotation=class_.getAnnotation(MyAnnotation.class);            
                if (myAnnotation !=null && myAnnotation instanceof MyAnnotation) {          
                    System.out.println(((MyAnnotation) myAnnotation).value()+((MyAnnotation) myAnnotation).age());            
                }            
                for (Method method : class_.getDeclaredMethods()) {                
                    MyAnnotation methodAnnotation=method.getAnnotation(MyAnnotation.class);                
                    if (methodAnnotation!=null) {           
                        System.out.println(methodAnnotation.value()+methodAnnotation.age());                
                    }            
                }        
            } catch (ClassNotFoundException e) {            
                e.printStackTrace();        
            }    
        }
    }
    

    果断打印出期望值

    defaultValue10
    Hello100
    

    实战2---教你写一个简单的类似ButterKnife工具

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface onClick {    
        int[] value();
    }
    

    这边如出一辙

    下面是简单的调度类,负责实际意义上的点击事件处理

    public class InjectorProcessor {    
        public void process(final Object object) {        
            Class class_=object.getClass();        
            Method[] methods=class_.getDeclaredMethods();        
            for (final Method method : methods) {            
                onClick clickMethod=method.getAnnotation(onClick.class);            
                if (clickMethod!=null) {                
                    if (object instanceof Activity) {                   
                        for (int id : clickMethod.value()) {                        
                            View view=((Activity) object).findViewById(id);                        
                            view.setOnClickListener(new View.OnClickListener() {                            
                                @Override                            
                                public void onClick(View v) {                                
                                    try {                                    
                                        method.invoke(object);                                
                                    } catch (IllegalAccessException e) {                                    
                                        e.printStackTrace();                                
                                    } catch (InvocationTargetException e) {                                    
                                        e.printStackTrace();                                
                                    }                            
                                }                        
                            });                    
                        }                
                    }            
                 }        
             }    
        }
    }
    

    最后使用就很简单了

    public class MainActivity extends AppCompatActivity {    
        @Override    
        protected void onCreate(Bundle savedInstanceState) {        
            super.onCreate(savedInstanceState);        
            setContentView(R.layout.activity_main);        
            InjectorProcessor processor=new InjectorProcessor();        
            processor.process(MainActivity.this);    
        }    
    
        @onClick({R.id.textview})    
        public void click() {        
            Toast.makeText(this, "HHH", Toast.LENGTH_SHORT).show();    
        }
    }
    

    相关文章

      网友评论

        本文标题:如何实现自定义Java运行时注解功能

        本文链接:https://www.haomeiwen.com/subject/qzrhdttx.html