Xutils之ViewUtils解析

使用:
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();
                          }
                      }
                  });
              }
          }
      }

  }
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值