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

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.效果展示

          在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值