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类的框架,你肯定不陌生~
ContentView
view
onClick
onlongclick
注入ContentView
注入View
注入事件
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(); } } } }