zoukankan      html  css  js  c++  java
  • Android annotation

    注解是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。

    在运行时读取需要使用Java反射机制进行处理。

    一、注解的作用:

    注解将一些本来重复性的工作,变成程序自动完成,简化和自动化该过程。比如用于生成Java doc,比如编译时进行格式检查,比如自动生成代码等,用于提升软件的质量和提高软件的生产效率。

    二、注解都有哪些

    1、Java提供了四种元注解,专门负责新注解的创建工作,即注解其他注解。

    @Target
    定义了Annotation所修饰的对象范围,取值: 

    ElementType.CONSTRUCTOR:用于描述构造器

    ElementType.FIELD:用于描述域

    ElementType.LOCAL_VARIABLE:用于描述局部变量

    ElementType.METHOD:用于描述方法

    ElementType.PACKAGE:用于描述包

    ElementType.PARAMETER:用于描述参数

    ElementType.TYPE:用于描述类、接口(包括注解类型) 或enum声明

    @Retention
    定义了该Annotation被保留的时间长短,取值:

     - RetentionPoicy.SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;用于做一些检查性的操作,比如 @Override 和 @SuppressWarnings
     - RetentionPoicy.CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;用于在编译时进行一些预处理操作,比如生成一些辅助代码(如 ButterKnife)
     - RetentionPoicy.RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在;用于在运行时去动态获取注解信息。
     

    @Documented
    标记注解,用于描述其它类型的注解应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化,不用赋值。

    @Inherited
    标记注解,允许子类继承父类的注解。 这里一开始有点理解不了,需要断句一下,允许子类继承父类的注解。

    2、Android SDK内置的注解

    Android SDK 内置的注解都在包com.android.support:support-annotations里,下面以'com.android.support:support-annotations:25.2.0'为例

    资源引用限制类:用于限制参数必须为对应的资源类型
    @AnimRes @AnyRes @ArrayRes @AttrRes @BoolRes @ColorRes等

    线程执行限制类:用于限制方法或者类必须在指定的线程执行
    @AnyThread @BinderThread @MainThread @UiThread @WorkerThread

    参数为空性限制类:用于限制参数是否可以为空
    @NonNull @Nullable

    类型范围限制类:用于限制标注值的值范围
    @FloatRang @IntRange

    类型定义类:用于限制定义的注解的取值集合
    @IntDef @StringDef

    其他的功能性注解:
    @CallSuper @CheckResult @ColorInt @Dimension @Keep @Px @RequiresApi @RequiresPermission @RestrictTo @Size @VisibleForTesting

    3、自定义注解。。。。

    三、如何使用Android Annotation

    build.gradle

    dependencies {
      androidTestCompile('com.android.support:support-annotations:26.1.0') {
        force = true
      }
    }

    举例子:

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

      

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

      

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

      

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ViewById {
        int value();
    }
    

      

    public class AnnotationParse {
    
    
        private static AnnotationParse instance;
    
        public static AnnotationParse getInstance() {
            if (instance == null) {
                synchronized (AnnotationParse.class) {
                    if (instance == null) {
                        instance = new AnnotationParse();
                        return instance;
                    }
                }
            }
            return instance;
        }
    
        public void bind(Activity activity) throws IllegalAccessException {
            try {
                injectLayout(activity);
                bindView(activity);
                bindOnClick(activity);
                injectEvent(activity);
            } catch (Exception ex) {
    
            }
        }
    
        private static void bindView(Activity activity) throws IllegalAccessException {
            //1、获取字节码
            Class<? extends Activity> aClass = activity.getClass();
    
            //2、获取Activity中变量
            Field[] declaredField = aClass.getDeclaredFields();
    
            for (Field field : declaredField) {
                //设置允许暴力反射
                field.setAccessible(true);
                //3、获取变量上的注释
                ViewById annotation = field.getAnnotation(ViewById.class);
                if (annotation != null) {
                    //4、获取注释上的值
                    int id = annotation.value();
                    //5、通过ID获取控件
                    View view = activity.findViewById(id);
                    //6、控件赋值给变量
                    field.set(activity, view);
                }
            }
        }
    
        //对OnClick注解的“解释”
        private static void bindOnClick(final Activity activity) {
            //1、获取字节码对象
            final Class<? extends Activity> aClass = activity.getClass();
            //2、获取所有的方法
            Method[] declaredMethods = aClass.getDeclaredMethods();
            //3、遍历所有的方法
            for (final Method method : declaredMethods) {
                method.setAccessible(true);
                //4、获取方法上的注释
                OnClick annotation = method.getAnnotation(OnClick.class);
                if (annotation != null) {
                    int id = annotation.value();
                    View view = activity.findViewById(id);
                    view.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            try {
                                //执行注解的方法
                                method.invoke(activity, null);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            }
        }
    
    
        private static void injectEvent(final Activity activity) {
            Class<? extends Activity> clazz = activity.getClass();
            Method[] methods = clazz.getDeclaredMethods();
            for (final Method method2 : methods) {
                BtnOnClick click = method2.getAnnotation(BtnOnClick.class);
                if (click != null) {
                    int[] viewId = click.value();
                    method2.setAccessible(true);
                    Object listener = Proxy.newProxyInstance(View.OnClickListener.class.getClassLoader(),
                            new Class[]{View.OnClickListener.class}, new InvocationHandler() {
                                @Override
                                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                    return method2.invoke(activity, args);
                                }
                            });
    
                    try {
                        for (int id : viewId) {
                            View v = activity.findViewById(id);
                            Method setClickListener = v.getClass().getMethod("setOnClickListener", View.OnClickListener.class);
                            setClickListener.invoke(v, listener);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
    
        private static int mLayoutId = -1;
    
        /**
         * 注解布局Layout id
         */
        private static void injectLayout(Activity activity) {
            Class<?> clazz = activity.getClass();
            if (clazz.getAnnotations() != null) {
                if (clazz.isAnnotationPresent(LayoutInject.class)) {
                    LayoutInject inject = clazz.getAnnotation(LayoutInject.class);
                    mLayoutId = inject.value();
                    activity.setContentView(mLayoutId);
                }
            }
    
        }
    
    }
    

      

    @LayoutInject(R.layout.activity_main)
    public class MainActivity extends AppCompatActivity {
    
        @ViewById(R.id.tvName)
        TextView tvName;
    
        @ViewById(R.id.tvAge)
        TextView tvAge;
    
        @ViewById(R.id.tvGender)
        TextView tvGender;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            //setContentView(R.layout.activity_main);
            try {
                AnnotationParse.getInstance().bind(this);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            tvName.setText("测试名字");
            tvAge.setText("28");
            tvGender.setText("男");
        }
    
        @BtnOnClick({R.id.tvName, R.id.tvAge, R.id.tvGender})
        public void btnOnClick(View view) {
            switch (view.getId()) {
                case R.id.tvName:
                    tvName.setText("华山论剑");
                    break;
                case R.id.tvAge:
                    tvAge.setText("四百多岁");
                    break;
                case R.id.tvGender:
                    tvGender.setText("女");
                    break;
            }
        }
    
    
        @OnClick(R.id.tvName)
        public void textOnClick() {
            tvName.setText("华山论剑");
        }
    }
    

      

  • 相关阅读:
    【k8s】pv 处在 Terminating 状态
    【k8s】命令行自动补全
    【k8s】允许 master 节点运行 pod
    【k8s】Harbor 安装
    Nginx 允许 frame 嵌套
    Python基础教程:json中load和loads区别
    Python 基础教程:用户交互语句
    Python正则表达式-常用函数的基本使用
    Python字典循环与字典排序
    4道Python文件操作和函数练习题
  • 原文地址:https://www.cnblogs.com/candyzhmm/p/12169808.html
Copyright © 2011-2022 走看看