美文网首页
自己动手打造一套IOC注解框架

自己动手打造一套IOC注解框架

作者: 如愿以偿丶 | 来源:发表于2019-09-29 21:38 被阅读0次

    1.概述

      什么是IOC,控制反转(Inversion of Control,英文缩写为IOC),其实就是反射加注解,Android IOC框架,其实主要就是帮大家注入所有的控件,布局文件什么的。如果你用过xUtils,Butterkinfe等框架,你肯定不陌生~

    2.框架实现

      大家有时间可以去看一下xUtils,Butterkinfe源码,这里不过多介绍,就直接开始了,我采用的方式是反射加注解和Xutils类似

      思路:
        1.定义属性注解,点击事件注解,网络检查注解。
        2.通过反射获取类的所有属性,遍历获取属性上的注解 ViewById 找到对应的value值,进行处理
        3.通过反射获取类的所有方法,遍历获取方法上的注解 OnClick CheckNet 找到对应的value值,设置点击事件等,进行处理

      2.1.定义属性控件注解
        /**
         * Created by ych on 2019/8/12.
         * Description: View属性注解的Annotation
         */
        
        //@Target(ElementType.FIELD) 表示Annotation的位置  FIELD属性上  METHOD方法上  TYPE类上 CONSTRUCTOR构造方法上
        @Target(ElementType.FIELD)
        //@Retention(RetentionPolicy.CLASS) 表示什么时候生效  CLASS编译时  RUNTIME运行时  SOURCE源码资源
        @Retention(RetentionPolicy.RUNTIME)
        public @interface ViewById {
        
            //表示可以 @ViewById(R.id.text_tv)
            int value();
        }
    
        /**
         * Created by ych on 2019/8/12.
         * Description: 使用在Activity  自定义View  Fragment
         */
        public class ViewUtils {
        
            /**
             * 目前使用Activity上
             *
             * @param activity
             */
            public static void inject(Activity activity) {
                inject(new ViewFinder(activity), activity);
            }
        
            /**
             * 自定义View上
             *
             * @param view
             */
            public static void inject(View view) {
                inject(new ViewFinder(view), view);
            }
        
            /**
             * Fragment上
             *
             * @param view
             * @param object 表示Fragment
             */
            public static void inject(View view, Object object) {
                inject(new ViewFinder(view), object);
            }
        
            /**
             * 兼容上边三个
             * @param finder
             * @param object 表示反射时需要执行的类  也就是Activity  Fragment View
             */
            public static void inject(ViewFinder finder, Object object) {
                injectFiled(finder, object);
            }
        
            /**
             * 注入属性
             * @param finder
             * @param object
             */
            private static void injectFiled(ViewFinder finder, Object object) {
                //1.获取类里面所有属性
                Class<?> clazz = object.getClass();
                //获取类中所有属性,包括私有和公有
                Field[] fields = clazz.getDeclaredFields();
                //2.获取ViewById的value
                for (Field field : fields) {
                    ViewById viewById = field.getAnnotation(ViewById.class);
                    if (viewById != null) {
                        int viewId = viewById.value();
                        //3.findViewById找到View
                        View view = finder.findViewById(viewId);
                        if (view!=null){
                            //能够注入所有修饰符  private public
                            field.setAccessible(true);
                            //4.动态注入到找到的View
                            try {
                                /**
                                 * object:代表我们的要注入的View  (Activity ,Fragment, View)
                                 * view:就是我们的要注解View (TextView,ImageView等等)
                                 */
                                field.set(object,view);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        }
    
      2.2.定义点击事件注解+网络检查注解
        /**
         * Created by ych on 2019/8/12.
         * Description: View点击事件注解Annotation
         */
        //注解作用在方法上
        @Target(ElementType.METHOD)
        //注解什么时候调用   RUNTIME运行时调用
        @Retention(RetentionPolicy.RUNTIME)
        public @interface OnClick {
            //方法上可以多个
            int[] value();
        }
    
        /**
         * Created by ych on 2019/8/12.
         * Description: View网络检查注解的Annotation
         */
        //@Target(ElementType.FIELD) 表示Annotation的位置  FIELD属性上  METHOD方法上  TYPE类上 CONSTRUCTOR构造方法上
        @Target(ElementType.METHOD)
        //@Retention(RetentionPolicy.CLASS) 表示什么时候生效  CLASS编译时  RUNTIME运行时  SOURCE源码资源
        @Retention(RetentionPolicy.RUNTIME)
        public @interface CheckNet {
        
        }
    
        /**
         * 注入事件
         * @param finder
         * @param object
         */
        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 click = method.getAnnotation(OnClick.class);
                if (click!=null){
                    int[] viewIds = click.value();
                    //3.findViewById找到对应的OnClick
                    for (int viewId : viewIds) {
                        View view =  finder.findViewById(viewId);
    
                        //拓展功能,是否需要检查网络   不为空检查网络
                        boolean isCheckNet = method.getAnnotation(CheckNet.class)!=null;
    
                        //4.设置点击事件setOnClickListent
                        view.setOnClickListener(new DeclaredOnClickListener(method,object,isCheckNet));
                    }
    
                }
            }
        }
    
        public static class DeclaredOnClickListener implements View.OnClickListener{
            private Method mMethod;
            private Object mObject;
            private Boolean isCheckNet;
            /**
             * @param method    方法
             * @param object    哪个页面上Activity
             */
            public DeclaredOnClickListener(Method method, Object object,boolean isCheckNet) {
                this.mMethod = method;
                this.mObject = object;
                this.isCheckNet = isCheckNet;
            }
            @Override
            public void onClick(View v) {
                //需不需要检查网络
                if (isCheckNet){
                    if (!networkAvailable(v.getContext())){
                        //这里写死是有问题的,需要配置
                        Toast.makeText(v.getContext(),"亲,您的网络不太给力",Toast.LENGTH_SHORT).show();
                        return;
                    }
                }
    
                mMethod.setAccessible(true);
                try {
                    //5.反射执行该方法
                    mMethod.invoke(mObject,v);
                } catch (Exception e) {
                    e.printStackTrace();
                    try {
                        mMethod.invoke(mObject,null);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    
        /**
         * 判断网络
         * @param context
         * @return
         */
        public static boolean networkAvailable(Context context) {
            try {
                if (context != null) {
                    ConnectivityManager mConnectivityManager = (ConnectivityManager) context
                            .getSystemService(Context.CONNECTIVITY_SERVICE);
                    NetworkInfo activeNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
                    if (activeNetworkInfo != null && activeNetworkInfo.isConnected()) {
                        return true;
                    }
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            return false;
        }
    

    3.使用

       public class TestActivity extends AppCompatActivity {
              private final String TAG = "TestActivity";
              
           //注解注入
           @ViewById(R.id.iv_skin)
           private ImageView mIvskin;
           
           @ViewById(R.id.btn_skin)
           private Button mBtnskin;
           
           @ViewById(R.id.btn_call)
           private Button mBtncall;
    
       
           @Override
           protected void onCreate(@Nullable Bundle savedInstanceState) {
               super.onCreate(savedInstanceState);
               setContentView(R.layout.activity_main);
               ViewUtils.inject(this);
           }
       
       
           //点击事件和网络注解
               @OnClick({R.id.iv_skin,R.id.btn_skin,R.id.btn_call})
               @CheckNet
            public void onClick(View view) {
                   switch (view.getId()){
                       case R.id.iv_skin:
                           Toast.makeText(this,"图片",Toast.LENGTH_SHORT).show();
                           break;
                       case R.id.btn_skin:
                           Toast.makeText(this,"换肤",Toast.LENGTH_SHORT).show();
                           break;
                       case R.id.btn_call:
                           Toast.makeText(this,"打电话",Toast.LENGTH_SHORT).show();
                           break;
               }
           }
       }
    

    4.效果展示

               在这里插入图片描述

    相关文章

      网友评论

          本文标题:自己动手打造一套IOC注解框架

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