使用: ViewUtils.inject(this, rootView); // fragment中 源码分析: public static void inject(Object handler, View view) { injectObject(handler, new ViewFinder(view)); //ViewFinder是对Fragment中的rootView或Activity的封装,方便调用findViewByid } @SuppressWarnings("ConstantConditions") private static void injectObject(Object handler, ViewFinder finder) { Class<?> handlerType = handler.getClass(); // activity/fragment // inject ContentView 对ContentView的注入,少用 ContentView contentView = handlerType.getAnnotation(ContentView.class); if (contentView != null) { try { Method setContentViewMethod = handlerType.getMethod("setContentView", int.class); setContentViewMethod.invoke(handler, contentView.value()); } catch (Throwable e) { LogUtils.e(e.getMessage(), e); } } // inject view 对view的注入,用于设置含有@ViewInject注解的View值 Field[] fields = handlerType.getDeclaredFields(); if (fields != null && fields.length > 0) { for (Field field : fields) { ViewInject viewInject = field.getAnnotation(ViewInject.class);// 获取含有ViewInject注解的field if (viewInject != null) { try { // 对于Activity:activity.findViewById(R.id.xxx) // 对于Fragment: viewRoot.findViewById(R.id.xxx) View view = finder.findViewById(viewInject.value(), viewInject.parentId()); if (view != null) { field.setAccessible(true); field.set(handler, view); } } catch (Throwable e) { LogUtils.e(e.getMessage(), e); } } } } // inject event 注入事件 Method[] methods = handlerType.getDeclaredMethods(); if (methods != null && methods.length > 0) { for (Method method : methods) { Annotation[] annotations = method.getDeclaredAnnotations(); // 获取所有含有注解的方法(如含有OnClick注解的方法) if (annotations != null && annotations.length > 0) {// 遍历Activity/Fragment中的所有含有注解的方法 for (Annotation annotation : annotations) { // 遍历所有方法上的注解 // 获取注解的注解。例:OnClick的注解上还有元注解为:EventBase Class<?> annType = annotation.annotationType(); // 注解类,比如OnClick注解。annType代表OnClick对象 if (annType.getAnnotation(EventBase.class) != null) { // 如果函数的注解的注解上还含有EventBase这种注解 method.setAccessible(true); // 获取OnClick注解上的value值,一般为R.id.XX(如某个Button的id) Method valueMethod = annType.getDeclaredMethod("value"); Method parentIdMethod = null; Object values = valueMethod.invoke(annotation); Object parentIds = parentIdMethod == null ? null : parentIdMethod.invoke(annotation); int parentIdsLen = parentIds == null ? 0 : Array.getLength(parentIds); // parentIdsLen为0 int len = Array.getLength(values); for (int i = 0; i < len; i++) { // R.id.xxx等数据都封装在ViewInjectInfo类中 ViewInjectInfo info = new ViewInjectInfo(); info.value = Array.get(values, i); // values==R.id.xxx info.parentId = parentIdsLen > i ? (Integer) Array.get(parentIds, i) : 0; // info:封装了OnClick注解中的数据信息R.id.xxx // finder类封装了Activity/Fragment的ViewRoot等信息 // method是Activity/Fragment中带有OnClick注解的方法对象 // annotation注解封装了OnClick注解 // handler:为Activity/Fragment EventListenerManager.addEventMethod(finder, info, annotation, handler, method); } } } } } } // TODO 该方法暂未解析,只知道设置监听方法到指定对象中 public static void EventListenerManager.addEventMethod( ViewFinder finder, ViewInjectInfo info, Annotation eventAnnotation, Object handler, Method method) { View view = finder.findViewByInfo(info); // 找到R.id.xxx对应的控件 if (view != null) { EventBase eventBase = eventAnnotation.annotationType().getAnnotation(EventBase.class); Class<?> listenerType = eventBase.listenerType(); // View.OnClickListener.class String listenerSetter = eventBase.listenerSetter(); // "setOnClickListener" String methodName = eventBase.methodName(); // "onClick" boolean addNewMethod = false; Object listener = listenerCache.get(info, listenerType); DynamicHandler dynamicHandler = null; if (listener != null) { dynamicHandler = (DynamicHandler) Proxy.getInvocationHandler(listener); addNewMethod = handler.equals(dynamicHandler.getHandler()); if (addNewMethod) { dynamicHandler.addMethod(methodName, method); } } if (!addNewMethod) { dynamicHandler = new DynamicHandler(handler); dynamicHandler.addMethod(methodName, method); listener = Proxy.newProxyInstance( listenerType.getClassLoader(), new Class<?>[]{listenerType}, dynamicHandler); listenerCache.put(info, listenerType, listener); } Method setEventListenerMethod = view.getClass().getMethod(listenerSetter, listenerType); setEventListenerMethod.invoke(view, listener); } } 总结: @ViewInject和@OnClick注解实现: 将Activity或者Fragment的RootView传递给ViewUtils中,ViewUtils对Activity或Fragment的RootView封装成ViewFinder,方便执行 findViewById。当ViewInjdect.inject的时候,反射找到所有含有ViewInject的注解的成员,执行findViewByid来设置View成员的值。 对于含有OnClick的方法,则执行setOnClickListener方法来设置成员函数注解View中 补充: // EventBase注解 @Target(ElementType.ANNOTATION_TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface EventBase { Class<?> listenerType(); String listenerSetter(); String methodName(); } // OnClick注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @EventBase( listenerType = View.OnClickListener.class, listenerSetter = "setOnClickListener", methodName = "onClick") public @interface OnClick { int[] value(); int[] parentId() default 0; } 简单的setOnClickListener实现 public class PanViewInjector { public static void process(final Object o) { Class c = o.getClass(); Method[] methods = c.getDeclaredMethods(); for (final Method m : methods) { OnClick click = m.getAnnotation(OnClick.class);//通过反射api获取方法上面的注解 if (click != null) { if (o instanceof Activity) { if (click.value() == -1) return; View view = ((Activity) o).findViewById(click.value());//通过注解的值获取View控件 if (view == null) return; view.setOnClickListener(new View.OnClickListener() { // 找到方法,重新设置监听,只是调用的方法为之前@OnClick设置的 @Override public void onClick(View v) { try { m.invoke(o);//通过反射来调用被注解修饰的方法 } catch (Exception e) { e.printStackTrace(); } } }); } } } } }
Xutils之ViewUtils解析
最新推荐文章于 2020-05-01 21:21:34 发布