Android 中的 IOC 框架

IoC,控制反转(Inversion of Control,英文缩写为IoC)
要完成IoC框架,首先你需要了解注解与发射
开始代码片段

Activity setContentView注解

@Retention(RetentionPolicy.RUNTIME)
public @interface ContentView {
    int value();
}

字段注解

@Retention(RetentionPolicy.RUNTIME)
public @interface BindView {
    int value();
}

事件三要素注解

@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BaseEvent {
    String setMethodName();
    Class interfaceClass();
    String callMethodName();
}

OnClick注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BaseEvent(setMethodName = "setOnClickListener", interfaceClass = View.OnClickListener.class, callMethodName = "onClick")
public @interface OnClick {
    int[] value();
}

OnLongClick注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BaseEvent(setMethodName = "setOnLongClickListener", interfaceClass = View.OnLongClickListener.class, callMethodName = "onLongClick")
public @interface OnLongClick {
    int[] value();
}

OnItemClick注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BaseEvent(setMethodName = "setOnItemClickListener", interfaceClass = AdapterView.OnItemClickListener.class, callMethodName = "onItemClick")
public @interface OnItemClick {
    int[] value();
}

动态代理

 * 动态代理
 */
public class EventInvocationHandler implements InvocationHandler {
    //代理的方法
    private Mapmap;
    //代理的真实对象
    private Object target;

    public EventInvocationHandler(Map map, Object target) {
        this.map = map;
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName=method.getName();
        if(map.get(methodName)!=null){
            return map.get(methodName).invoke(target,args);
        }
        return proxy;
    }
}

注解contentview实现

        //获取当前的类
        Class cls = context.getClass();
        //获取类上面的ContentView注解
        ContentView contentViewAnnotation = (ContentView) cls.getAnnotation(ContentView.class);
        if (contentViewAnnotation != null) {
            //获取注解上的值
            int value = contentViewAnnotation.value();
            try {
                //在类里面查找setContentView方法
                Method setContentViewMethod = cls.getMethod("setContentView", int.class);
                //setContentView调用
                setContentViewMethod.invoke(context, value);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

    }

注解字段的实现

        //获取当前的类
        Class cls = context.getClass();
        //查找对应的属性
        Field[] fields = cls.getFields();
        //遍历属性找到BindView注解
        for (Field field : fields) {
            BindView bindView = field.getAnnotation(BindView.class);
            if (bindView != null) {
                //获取注解的值
                int value = bindView.value();
                try {
                    //获取findVIewById方法
                    Method findViewByIdMethod = cls.getMethod("findViewById", int.class);
                    //调用findViewById方法拿到返回值
                    Object view = findViewByIdMethod.invoke(context, value);
                    field.setAccessible(true);
                    //设置属性值
                    field.set(context, view);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
    }

注解事件的实现

        //获取当前的类
        Class cls = context.getClass();
        //获取类中申明的可见方法
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            //获取方法上的所有注解
            Annotation[] annotations = method.getAnnotations();
            for (Annotation annotation : annotations) {
                //获取注解的类型 此处为OnClick OnLongClick
                Class annotationType = annotation.annotationType();
                //获取事件注解
                BaseEvent baseEvent = annotationType.getAnnotation(BaseEvent.class);
                if (baseEvent != null) {
                    //获取事件注解三要素
                    String setMethodName = baseEvent.setMethodName();
                    Class interfaceClass = baseEvent.interfaceClass();
                    String callMethodName = baseEvent.callMethodName();
                    //为动态代理做准备
                    Map map = new HashMap<>();
                    map.put(callMethodName, method);

                    try {
                        //获取注解的方法 值OnClick  OnLongClick
                        Method valueMethod = annotationType.getDeclaredMethod("value");
                        int[] values = (int[]) valueMethod.invoke(annotation);
                        for (int value : values) {
                            //通过注解的值 找到对应的view
                            Method findViewById = cls.getMethod("findViewById", int.class);
                            Object view = findViewById.invoke(context, value);
                            //获取事件的方法
                            Method setEventMethod = view.getClass().getMethod(setMethodName, interfaceClass);
                            //动态代理 代理context里面的方法
                            EventInvocationHandler eventInvocationHandler = new EventInvocationHandler(map, context);
                            Object proxy = Proxy.newProxyInstance(view.getClass().getClassLoader(), new Class[]{interfaceClass}, eventInvocationHandler);
                            //调用方法,通过动态代理最终执行context里面的方法
                            setEventMethod.invoke(view, proxy);
                        }
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
    }

上面只是简单的实现,可能的内存泄露,大家可以考虑使用引用相关的知识!

最后附上demo地址

你可能感兴趣的:(Android 中的 IOC 框架)