android 注解完成广播事件

在android中常常需要用到组件通信,activity-activity,activity-fragment,fragment-fragment很多时候需要不同的界面之间进行通信,而这个时候我们会想尽办法,比如采用接口,或者intent,或者setArguments()等等方法去进行数据或者参数传值,这个时候如果采用广播的话,就不需要做如此多繁琐且绞尽脑汁的事了,如果大家使用过eventBus的话,就知道我们只需要在一个组件中定义一个广播事件,然后在另一个组件中去接收就可以了,他们之间不需要建立任何的依赖关系,好了,说了这么多也不好理解,还是直接上代码好了,当然下面的代码是基于java的,不过activity也是一个class嘛,所以通用

  首先定义一个自定义注解,用于定义目标:

   

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface UIHandler{

	 String value();

}
然后定义一个注解操作类,即广播事件添加和通知的操作类:

package annotation.ui;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;


public class HandlerDispatcher {
	public static String TAG = HandlerDispatcher.class.getSimpleName();
	private static Map<String, Map<Object, Method>> clientMethod = new HashMap();

	
	/**
	 * 将类加入到注解map中
	 * @param obj 添加了注解的类
	 */
	public static void addUIHandler(Object obj) {
		if (obj == null) {
			System.out.println("the reflect object is null");
			return;
		}

		Class clzz = obj.getClass();
		// 反射拿到所有被注解的方法
		Method[] methods = clzz.getDeclaredMethods();
		Method[] arr$ = methods;

		int len$ = arr$.length;

		for (int i = 0; i < len$; i++) {
			Method method = arr$[i];

			// 得到具体的注解对象
			UIHandler uh = method.getAnnotation(UIHandler.class);
			if (uh != null) {
				String value = uh.value();
				if (value != null) {
					addClientMethods(value, obj, method);
					// 拿到值进行反射
					System.out.println("value:" + value);
				}
			}

		}
	}

	private static void addClientMethods(String value, Object client, Method m) {
		Object clientMap = clientMethod.get(value);
		if (clientMap == null) {
			clientMap = new HashMap();
			clientMethod.put(value, (Map<Object, Method>) clientMap);
		}
		((Map) clientMap).put(client, m);
	}

	public static void removeUIHandler(Object client) {
		if (client != null) {
			Iterator iterator = clientMethod.entrySet().iterator();
			while (iterator.hasNext()) {
				Entry entry = (Entry) iterator.next();
				String key = (String) entry.getKey();
				Map methods = clientMethod.get(key);
				if (methods != null) {
					System.out.println("remove success!");
					methods.remove(client);
				}
			}
		}
		// 另一种遍历,不过上面的遍历速度要快
		// for (String res : clientMethod.keySet()) {
		// Map meth=clientMethod.get(res);
		// meth.remove(client);
		// }
	}

	/**
	 * 通知到UI层刷新数据
	 *
	 * @param value
	 *            通知接收对应的值
	 * @param args
	 *            发送的参数
	 */
	public static void notifyClients(String value, Object... args) {
		if (value != null) {
			Map methods = clientMethod.get(value);
			if (methods != null) {
				Iterator iterator = methods.entrySet().iterator();
				// 异常捕获,可能出现通知错误的情况
				try {
					while (iterator.hasNext()) {
						Entry entry = (Entry) iterator.next();
						Object key = entry.getKey();//这个key应该就是开始存到map中的class
						Method m = (Method) methods.get(key);
						execute(key, m, args);
					}
				} catch (Throwable t) {
					System.out.println(t);
				}
			}
		}

	}

	/**
	 * 通过反射通知注解方法去接收消息
	 *
	 * @param key
	 * @param m
	 * @param args
	 */
	private static void execute(Object key, Method m, Object[] args) {
		if (m.getParameterTypes() == null)
		{
			System.out.println("注解方法属性为空");
			return;
		}
		m.setAccessible(true);//设置访问权限,避免方法被私有或者protected

		System.out.println("key:" + key);
		if (key instanceof Class) {
			try {
				m.invoke(key, args);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			System.out.println("don't invoke other attribute");
		}

	}
}

接着就是需要用到注解的类了,你可以把他当做一个activity

package annotation.uitest;

import annotation.ui.UIHandler;

public class AView {

	@UIHandler("getView")
	public void getView(String msg) {
		System.out.println(msg);
	}

	@UIHandler("test")//test这个字符串为自定义事件
	protected void getCount(String str) {
		System.out.println(str);
	}
}


最后就是测试了:

   

package annotation.uitest;

import annotation.ui.HandlerDispatcher;

public class UITest {

	public static void main(String[] args) {
		AView av = new AView();
		HandlerDispatcher.addUIHandler(av);
		// HandlerDispatcher.removeUIHandler(av);
		String str = "send a message";
		HandlerDispatcher.notifyClients("test", str);
		HandlerDispatcher.notifyClients("getView", "this is two msg");
	}

}

如上代码中,先将注解对象添加到注解map中,你可以在activity的oncreate方法中去调用该方法,如果要通用的话,就建一个activity的基类,将addUIHandler(activity)方法放在基类的oncreate中,然后下面的notifyClients就是通知了,注意第一个参数为通知的标记,这个一定要和接收通知的标记一样,否者无法收到通知,看完代码的话,其实大家就了解了,原理很简单,就是通过注解+反射来调用被注解的对象中的方法去完成广播+接收这样一个过程,当然这个通知应该有一些bug,不过欢迎大家指出

        最后,java中注解+反射其实是比较损耗性能的,对于执行效率和内存占用率暂时没去测试,后续有时间了,会仔细研究下的,但是现在android手机配置都那么高了,一点性能损耗其实是无碍的,哈哈



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值