Android关于注解那点事(一)

作者: 来自怀旧的你 | 来源:发表于2019-01-05 18:52 被阅读11次

    前言

    学习开发android已经1年多了,一直没有勇气和这个想法来写博客,记录一些东西,总觉得很麻烦(对,其实就是懒...),最近比较悠闲加上发现确实知识到达一定瓶颈了,需要开始总结反思一些东西,本人文笔确实也不太好,但凡事总得有个开始的过程,因为很多知识看的多,不代表会,只能自己实现过总结的东西才是属于自己的,这也是本人第一次写文章,水平有限,错误请及时指出,请各位大佬不吝指教,ths!

    1、例子

    话不多说,我们先上代码,看看注解到底能做什么,省的巴拉巴拉的知识点太枯燥了

    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
    
        @AnnoView(R.id.textView)
        TextView mTextView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            InjectManger.init(this);
        }
        @AnnoClick({R.id.textView})
        public void clickTest(View mView){
            switch (mView.getId()){
                case R.id.textView:
                    Toast.makeText(this,"click",Toast.LENGTH_LONG).show();
                    mTextView.setText("i am changed");
                    break;
            }
        }
    }
    

    这是主页面的activity代码,乍一看,诶。。好像有点熟悉的味道....我们看InjectManger做了啥

    public static void init(final Activity mActivity){
            Class<? extends Activity> aClass = mActivity.getClass();
            //通过反射获取到所有的成员变量
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field mfiled:declaredFields) {
            //判断如果成员变量的注解是AnnoView,获取到注解值
                if (mfiled.isAnnotationPresent(AnnoView.class)){
                    AnnoView annotation = mfiled.getAnnotation(AnnoView.class);
                    int value = annotation.value();
                    View viewById = mActivity.findViewById(value);
                    mfiled.setAccessible(true);
                    try {
                        mfiled.set(mActivity,viewById);
                    } catch (IllegalAccessException mE) {
                        mE.printStackTrace();
                    }
                }
            }
            Method[] declaredMethods = aClass.getDeclaredMethods();
            for (final Method methond: declaredMethods) {
                AnnoClick annotation = methond.getAnnotation(AnnoClick.class);
                if (annotation!=null){
                    int[] values = annotation.value();
                    for (int value:values) {
                        final View viewById = mActivity.findViewById(value);
                        viewById.setOnClickListener(new View.OnClickListener() {
                            @Override
                            public void onClick(View v) {
                                methond.setAccessible(true);
                                try {
                                    methond.invoke(mActivity,viewById);
                                } catch (IllegalAccessException mE) {
                                    mE.printStackTrace();
                                } catch (InvocationTargetException mE) {
                                    mE.printStackTrace();
                                }
                            }
                        });
                    }
                }
            }
        }
    

    然后我们看看对应的注解是啥

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

    注解很简单,表明对应的作用范围以及生命周期,具体@Target,@Retention啥意思,我们下面再说,相信聪明的朋友应该也能看的出来,对,说的就是你
    我们的最终效果来看下


    ezgif-2-f4abe9db8e34.gif

    gif是用Android stuio 录制的,效果感觉不太好,后续再改进,但基本也能看出来效果
    我们点击的时候触发了我们想要的效果,我们通过自己的注解形式完成了findViewById以及注册listner的工作,简单来说就是注解加上反射,像之前的Xutis大致原理也是如此,既然到这里了,我们就有必要了解注解到底是个啥东东。

    2、注解基础

    2.1.元注解

    元注解是由java提供的基础注解,负责注解其它注解,这话听起来好像有点绕,简单来说就是,虽你我都是注解,但是我比你牛批,你是需要我元注解来修饰的,比如说常见的元注解有

    • @Retention:注解保留的生命周期
    • @Target:注解对象的作用范围
    • @Inherited:标明所修饰的注解,在所作用的类上,是否可以被继承
    • @Documented:javadoc的工具文档化
      听起来好像很抽象,没事我们一个一个来看

    @Retention

    Retention说标明了注解被生命周期,表示你这个注解是什么时候开始生效的,对应有3种

    • SOURCE:源码级别生效
    • CLASS:编译class文件时生效
    • RUNTIME:运行时才生效
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }
    

    可以看到override是在源码级别就生效的,所以当你复写一个函数时,如果名称参数不对,是会报错的

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

    这是我们上篇例子的一个注解,可以看到是RUNTIME,也就是运行时才生效,还有一个class类型我们后续讨论

    @Target

    Target标明了注解的适用范围,对应的类型就比较多了,它明确的规定了使用的范围

    • TYPE:类、接口、枚举、注解类型。
    • FIELD:类成员(构造方法、方法、成员变量)。
    • METHOD:方法。
    • PARAMETER:参数。
    • CONSTRUCTOR:构造器。
    • LOCAL_VARIABLE:局部变量。
    • ANNOTATION_TYPE:注解。
    • PACKAGE:包声明。
    • TYPE_PARAMETER:类型参数。
    • TYPE_USE:类型使用声明。
      这个就比较易懂了,表示你这个注解要修饰的类型

    @Inherited

    • 类继承关系中,子类会继承父类使用的注解中被@Inherited修饰的注解
    • 接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有被@Inherited修饰
    • 类实现接口时不会继承任何接口中定义的注解
      具体大家可以写个单元测试验证一下,代码篇幅过长,这里就不贴上了,有需要的可以M我

    这篇就大概讲这么多了,太多了显得枯燥乏味,有兴趣的朋友可以跟着实现一下,但是我们都知道反射是比较消耗性能且效率低的,一个类里面有大量的注解,如果靠注解发射的话,效率难免会降低很多,emmmm,那你上面还讲那么多废话!咳咳...别激动别激动,文明社会,把板砖放下...这只是一种实现方式,下篇我们接着说另一种编译时注解的玩法

    溜了溜了..第一次写文章,感谢看到结尾,谢谢~~

    相关文章

      网友评论

        本文标题:Android关于注解那点事(一)

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