Android注解(annotation)实现绑定事件的原理

注解是一种很优雅的书写方式,也是我们的代码变的简洁,更加快捷方便编写代码。下面以绑定onclick实践为例阐述注解的原理。

1、定义Onclick注解类

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@BaseEvent(listenerSetter = "setOnclickListener", 
           listenerType = View.OnClickListener.class, 
           methodName = "onclick")
public @interface OnClick {
     int[] values();
}

BaseEvent用来制定需要绑定的方法名,事件的Listener,和绑定执行的方法名,BaseEvent的代码如下

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface BaseEvent {
	Class<?> listenerType();
	String listenerSetter();
	String methodName();
}

2、自定义的注解使用方式

 @OnClick(R.id.download_btn)
 public void testUpload(View view) {}

3、注解的解析(重点):

      思路:可以通过我们的注解对象中取得添加onclick注解的方法(testUpload)反射方法对象,对这个对象进行事件的绑定。动态代理View事件中的OnclickLister,向代理对象中添加方法对象(testUpload)。方法的添加在EventListenerManager管理类中完成。

     EventLisernerManager中定义动态代理类:

	public static void addEventMethod(Method method,
			Annotation annotation,
			Object value,
			Object handler,
			ViewFinder finder){
		try{
			View view = finder.findViewByInfo(value);
			if(view!=null){
				BaseEvent baseEvent = annotation.annotationType().getAnnotation(BaseEvent.class);
				Class<?> listenerType = baseEvent.listenerType();
				String listenerSetter = baseEvent.listenerSetter();
				String methodName = baseEvent.methodName();
				
				Object listener = listenerCache.get(value, listenerType);
				boolean addMethod =  false;
				DynamicHandler dymicHandler = null;
				if(listener!=null){
					dymicHandler = (DynamicHandler) Proxy.getInvocationHandler(listener);
					addMethod = (handler.equals(dymicHandler.getHandler()));
					if(addMethod){
						dymicHandler.addMethod(methodName, method);
					}
				}
				
				if(!addMethod){
					dymicHandler = new DynamicHandler(handler);
					dymicHandler.addMethod(methodName, method);
					listener = Proxy.newProxyInstance(listenerType.getClassLoader(), 
							   new Class<?>[]{listenerType},dymicHandler);
					listenerCache.put(value, listenerType, listener);
				}
				//setListener
				Method setterMethod = view.getClass().getMethod(listenerSetter, listenerType);
				setterMethod.invoke(view, listener);
			}
		}catch(Exception e){
			LogUtils.e(e.getMessage(),e);
		}
	}
listener = Proxy.newProxyInstance(listenerType.getClassLoader(),new Class<?>[]{listenerType},dymicHandler);动态的代理了onClickListener。类中对代理对象进行的缓存:

//缓存代理对象
public final static DoubleKeyValueMap<Object,Class<?>, Object> listenerCache = null;


解析注解添加方法:

		Method[] methods = handlerType.getDeclaredMethods();
		if(methods.length>0){
			for(Method method:methods){
				Annotation[] annotations = method.getDeclaredAnnotations();
				for(Annotation annotation : annotations){
					Class<?> anType = annotation.annotationType();//拿到Annotation的Class
					if(anType.getAnnotation(BaseEvent.class)!=null){
						method.setAccessible(true);
						try{
						Method valueMethod = anType.getDeclaredMethod("values");
						Object values = valueMethod.invoke(annotation);
						int len = Array.getLength(values);
						if(len>0){
							for(int i=0;i<len;i++){
							   Object value = Array.get(values, i);
							   EventListenerManager.addEventMethod(method, annotation, value, handlerType, finder);
							}
					    }
						}catch(Exception e){
							e.printStackTrace();
						}
					}
				}
			}
		}
        这里可以拿到自定义method和注解本身。不太了解的可以研究下java的annotation的用法。

由以上的方法的可以实现注解事件的绑定,可以自己定义事件的注解,优雅的开始你的代码吧!











Android注解(annotation)实现绑定事件的原理

上一篇:【WP 8.1开发】解决摄像头翻转问题(RuntimeApp篇)


下一篇:jQuery.FlexiGrid使用总结