在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手机配置都那么高了,一点性能损耗其实是无碍的,哈哈