注解

作者: 内卷程序员 | 来源:发表于2022-08-30 11:12 被阅读0次

    注解是 JDK5 之后的新特性,是一种特殊的注释,它为提供了在代码中添加信息的新的方式

    注解定义

    • 定义注解的时候需要@interface
    • 参数的类型只能是public或者不写两种访问修饰符
    • 注解参数定义类似于抽象方法声明,返回值就是其类型
    • 注解参数必须有确切的值,要么在定义注解的默认值中指定,要么在使用注解时指定,注解参数的可支持数据类型 如下:

    基本数据类型(int,float,boolean,byte,double,char,long,short)
    String类型
    Class类型
    enum类型
    Annotation类型
    以上所有类型的数组

    //运行时注解,并采用反射方法调用执行。
    // 1.绑定控件注解
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Bind {
        int value();
        int[] parentId() default 0;
    }
    // 2.检查网络注解 
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface CheckNet {
       //是一个空注解,用的时候直接标注
    }
    // 3.绑定事件注解
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface OnClick {
        int[] value();
       //如果注解的参数有默认值,在使用的时候如果不需要赋值可以不写这个参数
        int[] parentId() default 0;
    }
    // 4. 绑定布局
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface ContentView {
        int value();
       //如果注解只有一个参数, 尽量使用value来表示参数,这样在使用的时候可以直接 @ContentView (R.id.xxx),而不需要使用@ContentView (value=R.id.xxx)
    }
    

    元注解

    元注解,就是用来定义和实现注解的注解,一共有四种

    • @Target :用来指定注解所适用的对象范围 (ElementType类型的数组)
    元素类型 作用范围
    ANNOTATION_TYPE 注解类型声明
    CONSTRUCTOR 构造函数
    FIELD 实例变量
    LOCAL_VARIABLE 局部变量
    METHOD 方法
    PACKAGE
    PARAMETER 方法参数或者构造函数的参数
    TYPE 类(包含enmu)和接口(包含注解类型)
    TYPE_PARAMETER 类型参数
    TYPE_USER 类型的用图
    • @Retention :表示需要在什么级别保存该注解信息
    元素类型 保留级别
    RetentionPolicy.SOURCE 该类型的注解信息只会保留在.java源码里,编译的时候注解将被编译器丢弃,其功能是与编译器交互,比如用于代码检测,@Override,@SuppressWarings
    RetentionPolicy.CLASS 该注解的注册信息会保留在.java源码里和.class文件里,在执行的时候,会被java虚拟机丢弃,不会加载到虚拟机中,主要用于编译时生成额外的文件,如XML,Java文件等,APT
    RetentionPolicy.RUNTIME 运行时级别,注解存在源码,字节码与Java虚拟机中,可以通过反射机制读取注解的信息, 许多框架如OrmLite就是使用这个级别的注解
    • @Documented:表示将此注解包含在Javadoc中
    • @Inherited:表示允许子类继承父类中的注解

    注解使用

      // 获取类型指定注解
      <T extends Annotation> T getAnnotation(Class<T> annotationClass) 
     //获取该类的所有注解
      Annotation[] getAnnotations() 
    
    public class ViewInjectorImpl implements ViewInject {
    
        private ViewInjectorImpl() {
        }
    
        public static ViewInjectorImpl mInstance;
    
        public static ViewInjectorImpl getInstance() {
            if (mInstance == null) {
                synchronized (ViewInjectorImpl.class) {
                    if (mInstance == null) {
                        mInstance = new ViewInjectorImpl();
                    }
                }
            }
            return mInstance;
        }
    
        @Override
        public void inject(View view) {
            injectObject(view, view.getClass(), new ViewFinder(view));
        }
    
        @Override
        public void inject(Object handler, View view) {
            injectObject(handler, view.getClass(), new ViewFinder(view));
        }
    
        @Override
        public void inject(Activity activity) {
            Class<?> clazz = activity.getClass();
            // activity设置布局
            try {
                ContentView contentView = findContentView(clazz);
                if (contentView != null) {
                    int layoutId = contentView.value();
                    if (layoutId > 0) {
                        Method setContentView = clazz.getMethod("setContentView", int.class);
                        setContentView.invoke(activity, layoutId);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            injectObject(activity, clazz, new ViewFinder(activity));
        }
    
        @Override
        public View inject(Object fragment, LayoutInflater inflater, ViewGroup container) {
            Class<?> clazz = fragment.getClass();
            // fragment设置布局
            View view = null;
            ContentView contentView = findContentView(clazz);
            if (contentView != null) {
                int layoutId = contentView.value();
                if (layoutId > 0) {
                    view = inflater.inflate(layoutId, container, false);
                }
            }
            injectObject(fragment, clazz, new ViewFinder(view));
            return view;
        }
    
        /**
         * 从类中获取ContentView注解
         *
         * @param clazz
         * @return
         */
        private static ContentView findContentView(Class<?> clazz) {
            return clazz != null ? clazz.getAnnotation(ContentView.class) : null;
        }
    
        public static void injectObject(Object handler, Class<?> clazz, ViewFinder finder) {
            try {
                injectView(handler, clazz, finder);
                injectEvent(handler, clazz, finder);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 设置findViewById
         *
         * @param handler
         * @param clazz
         * @param finder
         */
        @SuppressWarnings("ConstantConditions")
        private static void injectView(Object handler, Class<?> clazz, ViewFinder finder) throws Exception {
            // 获取class的所有属性
            Field[] fields = clazz.getDeclaredFields();
    
            // 遍历并找到所有的Bind注解的属性
            for (Field field : fields) {
                Bind viewById = field.getAnnotation(Bind.class);
                if (viewById != null) {
                    // 获取View
                    View view = finder.findViewById(viewById.value(), viewById.parentId());
                    if (view != null) {
                        // 反射注入view
                        field.setAccessible(true);
                        field.set(handler, view);
                    } else {
                        throw new Exception("Invalid @Bind for "
                                + clazz.getSimpleName() + "." + field.getName());
                    }
                }
    
            }
        }
    
        /**
         * 设置Event
         *
         * @param handler
         * @param clazz
         * @param finder
         */
        @SuppressWarnings("ConstantConditions")
        private static void injectEvent(Object handler, Class<?> clazz, ViewFinder finder) throws Exception {
            // 获取class所有的方法
            Method[] methods = clazz.getDeclaredMethods();
    
            // 遍历找到onClick注解的方法
            for (Method method : methods) {
                OnClick onClick = method.getAnnotation(OnClick.class);
                OnItemClick onItemClick = method.getAnnotation(OnItemClick.class);
                boolean checkNet = method.getAnnotation(CheckNet.class) != null;
                if (onClick != null) {
                    // 获取注解中的value值
                    int[] views = onClick.value();
                    int[] parentIds = onClick.parentId();
                    int parentLen = parentIds == null ? 0 : parentIds.length;
                    for (int i = 0; i < views.length; i++) {
                        // findViewById找到View
                        int viewId = views[i];
                        int parentId = parentLen > i ? parentIds[i] : 0;
                        View view = finder.findViewById(viewId, parentId);
                        if (view != null) {
                            // 设置setOnClickListener反射注入方法
                            view.setOnClickListener(new MyOnClickListener(method, handler, checkNet));
                        } else {
                            throw new Exception("Invalid @OnClick for "
                                    + clazz.getSimpleName() + "." + method.getName());
                        }
                    }
                }
    
                if (onItemClick != null) {
                    // 获取注解中的value值
                    int[] views = onItemClick.value();
                    int[] parentIds = onItemClick.parentId();
                    int parentLen = parentIds == null ? 0 : parentIds.length;
                    for (int i = 0; i < views.length; i++) {
                        // findViewById找到View
                        int viewId = views[i];
                        int parentId = parentLen > i ? parentIds[i] : 0;
                        AdapterView view = (AdapterView) finder.findViewById(viewId, parentId);
                        if (view != null) {
                            // 设置setOnItemClickListener反射注入方法
                            view.setOnItemClickListener(new MyOnItemClickListener(method, handler, checkNet));
                        } else {
                            throw new Exception("Invalid @OnItemClick for "
                                    + clazz.getSimpleName() + "." + method.getName());
                        }
                    }
                }
            }
        }
    
        private static class MyOnClickListener implements View.OnClickListener {
            private Method method;
            private Object handler;
            private boolean checkNet;
    
            public MyOnClickListener(Method method, Object handler, boolean checkNet) {
                this.method = method;
                this.handler = handler;
                this.checkNet = checkNet;
            }
    
            @Override
            public void onClick(View v) {
                if (checkNet && !NetStateUtil.isNetworkConnected(v.getContext())) {
                    Toast.makeText(v.getContext(), "网络错误!", Toast.LENGTH_SHORT).show();
                    return;
                }
    
                // 注入方法
                try {
                    method.setAccessible(true);
                    method.invoke(handler, v);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    
        private static class MyOnItemClickListener implements AdapterView.OnItemClickListener {
            private Method method;
            private Object handler;
            private boolean checkNet;
    
            public MyOnItemClickListener(Method method, Object handler, boolean checkNet) {
                this.method = method;
                this.handler = handler;
                this.checkNet = checkNet;
            }
    
            @Override
            public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
                if (checkNet && !NetStateUtil.isNetworkConnected(v.getContext())) {
                    Toast.makeText(v.getContext(), "网络错误!", Toast.LENGTH_SHORT).show();
                    return;
                }
    
                // 注入方法
                try {
                    method.setAccessible(true);
                    method.invoke(handler, parent, v, position, id);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } 
    }
    
    //在BaseActivity中的onCreate中初始化。ViewInjectorImpl .inject(this);
    
    @ContentView(R.layout.activity_main)
    public class MainActivity extends BaseActivity {
    
      // 绑定控件
      @Bind(R.id.viewpager)
      ViewPager viewpager;
    
      // 绑定事件并检查网络
      @OnClick(R.id.dialog)
      @CheckNet
     void showDialog(TextView tv) {
        Intent intent = new Intent(getActivity(), DialogViewActivity.class);
        startActivity(intent);
     }
    }
    

    相关文章

      网友评论

          本文标题:注解

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