IOC依赖注入

1,IOC:控制反转,不是一门技术,而是一种思想,IOC有一个专门的容器来创建这些对象,然后给需要的对象使用,这种由容器来帮忙创建及注入依赖的方式叫控制反转,就是本来有自己创建的依赖变成别人创建给你直接使用,所以说反转了

2,定义一个注解是通过@interface来定义,注解只能定义方法

3,注解两大元素:@Target 与@Retention;

          @Target:定义我们的注解的目标是什么,通过ElementType来控制,常用的三个属行:TYPE(注解类)FIELD(字段)METHOD(方法)ANNOYTATION_TYPE(定义注解使用)

         @Retention:定义存活时间,SOURCE(源码阶段)CLASS(编译期)RUNTIME(存活到运行期)

4,实现layout注入:

//创建inject类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectLayout {

    int value();
}

//注入类实现方法
    /**
     * setContentView方法
     * @param obj
     */
    private static void injectLayout(Object obj) {
        //反射需要先获取Class对象
        //首先通过getClass来获取class对象
        Class<?> aClass = obj.getClass();
        //通过Class的getAnnotation 来获取inject的注解对象对象
        InjectLayout annotation = aClass.getAnnotation(InjectLayout.class);
//        判断注解对象是否为空,因为有可能没有InjectLayout的注解
        if (annotation!=null){
//            通过注解对象获取到传入的文件ID
            int value = annotation.value();
            try {
                //通过getMethod来setContentView获取方法
                Method method = aClass.getMethod("setContentView", int.class);
//                通过invoke来给方法赋值
                method.invoke(obj,value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

//activity使用

@InjectLayout(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {

实现控件的注入

//创建注入类

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

//实现方法
   /**
     * 成员变量的方法依赖
     * @param obj
     */
    private static void injectView(Object obj) {
        //首先获取class
        Class<?> aClass = obj.getClass();
        //因为成员变量有多个,所以我们通过getDeclaredFields来获取所有的成员变量
        Field[] declaredFields = aClass.getDeclaredFields();
//        通过遍历成员变量来获取变量的依赖注入类
        for (Field field:declaredFields){
            InjectView injectView = field.getAnnotation(InjectView.class);
//            因为有对象没有注入的对象,所以通过判空的方式判断是否需要
            if (injectView!=null){
//                获取到控件ID
                int value = injectView.value();
                try {
                    //通过class的getMethod来获取findViewById的方法对象
                    Method method = aClass.getMethod("findViewById", int.class);
                    //给对象赋值,到此实现了findViewById的代码,但是我们还需要将它赋值给我们的成员变量
                    Object view = method.invoke(obj, value);
                    //设置作用域
                    field.setAccessible(true);
                    //给成员变量赋值
                    field.set(obj,view);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        }
    }

//activity使用


    @InjectView(R.id.btn1)
    private Button btn1;




方法注入:因为方法可能有多个;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@InjectEvent(listenerSetter = "setOnClickListener",listener = View.OnClickListener.class,callBack = "onClick")
public @interface InjectOnClick {
    //因为方法的传参可能不止一个控件,所以返回值使用数组
    int[] value();
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@InjectEvent(listenerSetter = "setOnLongClickListener",listener = View.OnLongClickListener.class,callBack = "onLongClick")
public @interface InjectOnLongClick {
    //因为方法的传参可能不止一个控件,所以返回值使用数组
    int[] value();
}
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectEvent {
//     btn1.setOnClickListener(new View.OnClickListener() {
//        @Override
//        public void onClick(View view) {
//            Log.e("whf","btn1_onclick");
//        }
//    });
    //监听方法名
    String listenerSetter();
    //监听类
    Class listener();
//    监听的回调方法名
    String callBack();

}

因为不确定传入是点击还是长按事件,对应的Class不确定,所以需要设置代理需要用到InvocationHandler

public class ListenerInvocationHandler implements InvocationHandler {

    private Object object;
    private Method myMethod;

    public ListenerInvocationHandler(Object object, Method myMethod) {
        this.object = object;
        this.myMethod = myMethod;
    }

    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {

//可以判断是否使用这个方法
        return myMethod.invoke(object,objects);
    }
}
   private static void injectEvent(Object obj) {
        //获取class
        Class<?> aClass = obj.getClass();

        //首先获取class所有的方法,因为可能不止一个方法注释
        Method[] declaredMethods = aClass.getDeclaredMethods();
        //循环遍历方法,判断该方法是否有注入
        for (Method method:declaredMethods){
            //方法的注入可能不止一个,所以我们获取所有的注入类,进行循环判断
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation:annotations){
               /* //有一种傻瓜式方式实现,了解就好,不建议使用
                if (annotation.annotationType().getSimpleName().equals("111")){

                }else if (annotation.annotationType().getSimpleName().equals("222")){

                }*/

                //获取annotation的class对象
                Class<? extends Annotation> annotationType = annotation.annotationType();
                //我们可以通过定义注解的方式来处理不同的事件
                InjectEvent injectEvent = annotationType.getAnnotation(InjectEvent.class);
//                获取监听的方法名,需要传入的对象,callback
                String listenerSetter = injectEvent.listenerSetter();
                Class listener = injectEvent.listener();
                String callBack = injectEvent.callBack();

                try {
                    ListenerInvocationHandler listenerInvocationHandler = new ListenerInvocationHandler(obj, method);
                    Object proxyInstance = Proxy.newProxyInstance(listener.getClassLoader(),
                            new Class[]{listener}, listenerInvocationHandler);
                    //因为我们的value是子类的方法,我们接收的对象是Annotation,无法通过annotation。value()来获取对象,所以我们通过class的getMethod方法来获取
                    Method valueMethod = annotationType.getMethod("value");
//                    通过方法的invoke方法来获取值
                    int[] ids = (int[]) valueMethod.invoke(annotation);

                    for (int id:ids){
//                        通过class的findViewById方法来获取view

                        //通过class的getMethod来获取findViewById的方法对象
                        Method findViewById = aClass.getMethod("findViewById", int.class);
                        //给对象赋值,到此实现了findViewById的代码,但是我们还需要将它赋值给我们的成员变量
                        Object view = findViewById.invoke(obj, id);
//                        通过view的getMethod 获取需要设置的method方法
                        Method setterMethod = view.getClass().getMethod(listenerSetter, listener);
                        setterMethod.setAccessible(true);
                        setterMethod.invoke(view,proxyInstance);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }


            }
        }

    }

activity使用:


    @InjectOnClick({R.id.btn1,R.id.btn2})
    public void whfOnClick(View view) {

        Log.e("whf","whfOnClick");
    }
    @InjectOnLongClick({R.id.btn1,R.id.btn2})
    public boolean whfOnLongClick(View view) {

        Log.e("whf","whfOnLongClick");
        return false;
    }

源码下载地址:https://download.csdn.net/download/feng_zhongsha/16636507?spm=1001.2014.3001.5501

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值