Android-基于IOC的布局,控件,事件注入

 首先我们说说java元注解

@Target(注解的作用目标) @Retention(注解的保留位置)

@Ducument(说明该注解将包含在javadoc中) @Inherited(说明子类可以继承父类中的该注解)

1, @Target(ElmentType.Type)   //同下

  ElementTypeTYPE      类、接口(包括注释类型)或枚举声明

  ElementTypeFIELD     字段声明(包括枚举常量)

  ElementTypeMETHOD    方法声明

  ElementTypePARAMETER     参数声明

  ElementTypeCONSTRUCTOR    构造方法声明

  ElementTypeLOCAL_VARIABLE     局部变量声明

  ElementTypeANNOTATION_TYPE     注释类型声明

  ElementTypePACKAGE    包声明

2,@Retention(RetentionPolicy.SOURCE)//注解仅存在于源码中,在class字节码文件中不包含

@Retention(RetentionPolicy.CLASS)//注解class会字节码中,运行时无法获取,(默认策略)

@Retention(RetentionPolicy.RUNTIME)//注解会在class字节码中存在,运行时可以通过反射获取

框架实现

得进入正题了,Android IOC框架,其实主要就是帮大家注入所有的控件,布局文件什么的。如果你用过xUtils,afinal类的框架,你肯定不陌生~

Android-基于IOC的布局,控件,事件注入

ContentView

Android-基于IOC的布局,控件,事件注入

view

Android-基于IOC的布局,控件,事件注入

onClick

Android-基于IOC的布局,控件,事件注入

onlongclick

Android-基于IOC的布局,控件,事件注入


注入ContentView

Android-基于IOC的布局,控件,事件注入

注入View

Android-基于IOC的布局,控件,事件注入

注入事件

     EventBase

@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventBase {

    /**
     * 设置监听的方法
     * @return
     */
    String listenerSetter();

    /**
     * 事件类型
     * @return
     */
    Class<?> listenerType();

    /**
     * 回调方法
     * 事件被触发后,执行回调方法名称
     * @return
     */
    String callBackMethod();
}

ListenerInvocationHandler

public class ListenerInvocationHandler implements InvocationHandler {
    //activity   真实对象
    private Context context;
    private Map<String, Method> methodMap;

    public ListenerInvocationHandler(Context context, Map<String, Method> methodMap) {
        this.context = context;
        this.methodMap = methodMap;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String name = method.getName();
        //决定是否需要进行代理
        Method metf = methodMap.get(name);

        if (metf != null) {
            return metf.invoke(context, args);
        } else {
            return method.invoke(proxy, args);
        }
    }
}

click点击长按事件

/**
 * 注入点击和长按事件
 * @param context
 */
private static void injectEvents(AppCompatActivity context) {
    Class<?> clazz = context.getClass();
    Method[] methods = clazz.getDeclaredMethods();

    for (Method method : methods) {
        //获取方法上所有的注解
        Annotation[] annnotions = method.getAnnotations();
        for (Annotation annotation : annnotions) {

            //获取注解annotionType onClick OnLongClick
            Class<?> annotionType = annotation.annotationType();

            //获取注解的注解 onClick注解上面的EventBase
            EventBase eventBase = annotionType.getAnnotation(EventBase.class);
            if (eventBase == null) {
                continue;
            }
            //开始获取事件三要素 1 通过反射注入进去
            String listenerSetter = eventBase.listenerSetter();

            //2 得到listenrType-------->View.OnClickListener.class
            Class<?> listenerType = eventBase.listenerType();

            //3 callmethod----->onClick
            String callMethod = eventBase.callBackMethod();

            //方法名 与方法Method的对应关系
            Map<String, Method> methodMap = new HashMap<>();
            methodMap.put(callMethod, method);//eg:key:onClick(自己定义的)======value:MainActivity.onClick(Activity中的)

            try {
                Method valueMethod = annotionType.getDeclaredMethod("value");
                int[] viewIds = (int[]) valueMethod.invoke(annotation);

                for (int viewId : viewIds) {
                    //通过反射拿到View
                    Method findViewById = clazz.getMethod("findViewById", int.class);
                    View view = (View) findViewById.invoke(context, viewId);
                    if (view == null) {
                        continue;
                    }

                    Method setOnClickListener = view.getClass().getMethod(listenerSetter, listenerType);

                    ListenerInvocationHandler handler = new ListenerInvocationHandler(context, methodMap);

                    //proxy 已经实现了listenerType接口
                    Object proxy = Proxy.newProxyInstance(
                            listenerType.getClassLoader(),
                            new Class[]{listenerType}, handler);
                    //接口里的方法有proxy来处理
                    setOnClickListener.invoke(view, proxy);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

}