打造一套自己的注解框架

打造一套自己的注解框架

1.Xutils源码阅读与使用

// handlerType --> class  获取setContentView()方法
Method setContentViewMethod=handlerType.getMethod("setContentView", int.class);
// 反射执行该方法
setContentViewMethod.invoke(activity, viewId);
View view = finder.findViewById(viewInject.value(),viewInject.parentId());
if (view != null) {  
  // 可以操作所有修饰
  field.setAccessible(true);
  // 反射注入属性
  field.set(handler, view);
  }

属性注入:利用反射去获取Annotation->value->findViewById->反射注入属性
事件注入:利用反射去获取Annotation->value->findViewById->setOnClickListener->动态代理注入事件

2.ButterKnife源码阅读与使用

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

@Retention(CLASS)编译时的注解
1.编译的时候ButterKnifeProcessor 生成 .java --> class文件

2.运行时viewBinder.bind(finder, target, source);

3.自己打造一套注解框架

3.1 findViewById注入

1.在使用注解绑定控件的時候,一定记得在onCreate中调用ViewUtils.inject(this);
2.与ButterKnife不同的是我们采用的是运行时生效,Retention是说什么时候生效,分为三种情况,编译时生效class,运行时生效Runtime,源码资源Source.

//ViewByID.class
//代表Annotation 的位置
@Target(ElementType.FIELD)
//什么时候生效, 编译时生效Class 运行时生效Runtime 源码资源Source
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewById {
     int value();
}

3.ViewUtils中注入属性(因为考虑到了事件比如onClick等以及findViewById的绑定等,所以inject分成两步走,一部分是injectFiled,一部分是injectEvent)

 //注入属性
 private static void injectFiled(ViewFinder finder, Object object) {
         //1.获取类里面的所有属性
        Class<?>  clazz=object.getClass();
        //获取所有的属性,包括公有和私有
        Field[] fields=clazz.getDeclaredFields();
        //2.获取findById的里面的value 值
        for(Field field :fields){
            ViewById viewById=field.getAnnotation(ViewById.class);
            if(viewById !=null){
                //获取注解里面的id值  ---->R.id.test_iv
                int viewId=viewById.value();
                //3.findViewById 找到View
                View view=finder.findViewById(viewId);
                if(view !=null) {
                    //能够注入所有修饰符  例如private、public
                    field.setAccessible(true);
                    //4.动态的注入找到的View
                    try {
                        field.set(object, view);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
             }
          }
        }
3.2 事件的注入

1.onClick.class

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

2.事件的注入

 /**
     *
     * 事件注入
     */
    @RequiresApi(api = Build.VERSION_CODES.N)
    private static void injectEvent(ViewFinder finder, Object object) {
        //1.获取类里面所有的方法
        Class<?>  clazz=object.getClass();
        Method[] methods=clazz.getDeclaredMethods();
        //2.获取OnClick里面的value值
        for(Method method:methods){
            OnClick onClick=method.getAnnotation(OnClick.class);
            if(onClick !=null){
                int[] viewIds=onClick.value();
                for(int viewId :viewIds){
                    //3.findViewById找到View
                    View view=finder.findViewById(viewId);
                    //拓展功能 检测网络
                    boolean isCheckNet=method.getAnnotation(CheckNet.class) !=null;
                    if(view!=null){
                        //4.view.setOnClickListener
                        view.setOnClickListener(new DecalredOnclickListener(method,object,isCheckNet));
                    }
                }
            }
        }
    }

    private static class DecalredOnclickListener implements View.OnClickListener {
        private  Object mObject;
        private Method mMethod;
        private boolean mIsCheckNet;
        public DecalredOnclickListener(Method method, Object object,boolean isCheckNet) {
                this.mObject=object;
                this.mMethod=method;
                this.mIsCheckNet=isCheckNet;
        }

        @Override
        public void onClick(View v) {
            //需不需要监测网络
            if(mIsCheckNet){
                if(!networkAvalible(v.getContext())){
                    Toast.makeText(v.getContext(),"请检查您的网络环境",Toast.LENGTH_LONG).show();
                    return;
                }
            }
            //5.反射执行方法
            //点击会调用该方法
            try {
                mMethod.setAccessible(true);
                mMethod.invoke(mObject,v);
            } catch (Exception e) {
                e.printStackTrace();
              try {
                    mMethod.invoke(mObject,null);
              } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
    private static  boolean networkAvalible(Context context){
        try {
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
            if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
                return true;
            }
        }catch(Exception e){
                e.printStackTrace();
            }
        return false;
    }

injectEvent->DeclaredClickListener->netWorkAvalibe

4.APO和OOP

APO是面向切面的,通过注解、反射、动态代理(预编译方式和运行期动态代理)等方式实现,通俗的来说就是把跟性能有关的功能与同一个切面绑定。
OOP是面向对象的
APO

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值