这个功能是在公司项目需求的时候写出来,本来是基础命令字模式的,但是个人喜欢对象,所有后来在一个小项目中使用时,改成了基于对象模式。
首先,是一个接口,我们称之为监听器:
[html] view
plaincopyprint?
- /**
- *
- * @author poet
- *
- */
- public interface MessageObserver<T> {
- void onMessage(T t);
- }
这里使用的是泛型,泛型<T>除了作为实际监听的对象类型,也作为监听器管理的key,届时,你将收到一个具体类型的对象。下面是关键代码:
[java] view
plaincopyprint?
- package com.poet.lib.base.data;
- import java.lang.reflect.ParameterizedType;
- import java.lang.reflect.Type;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Map;
- import java.util.Set;
- import android.os.Handler;
- import android.os.Looper;
- /**
- * 基于对象的消息分发器
- * @author poet
- *
- */
- public class MessageDispatcher {
- private static Handler sHandler;
- private static Map<Class<?>, Set<MessageObserver<?>>> sMap;
- /**
- * 分发消息(可以在子线程调用)
- * @param t
- * @return 是否有监听器监听该消息
- */
- public static <T> boolean dispatch(final T t) {
- if (t == null) {
- throw new IllegalArgumentException("参数不可为null");
- }
- final Set<MessageObserver<?>> set;
- if (sMap == null || (set = sMap.get(t.getClass())) == null
- || set.isEmpty()) {
- return false;
- }
- if (sHandler == null) {
- sHandler = new Handler(Looper.getMainLooper());
- }
- sHandler.post(new Runnable() {
- @Override
- public void run() {
- synchronized (MessageDispatcher.class) {
- for (MessageObserver<?> item : set) {
- @SuppressWarnings("unchecked")
- MessageObserver<T> ob = (MessageObserver<T>) item;
- ob.onMessage(t);
- }
- }
- }
- });
- return true;
- }
- public synchronized static void addObserver(MessageObserver<?> ob) {
- Class<?> clazz = checkObserver(ob);
- if (sMap == null) {
- sMap = new HashMap<Class<?>, Set<MessageObserver<?>>>();
- }
- Set<MessageObserver<?>> set = sMap.get(clazz);
- if (set == null) {
- sMap.put(clazz, set = new HashSet<MessageObserver<?>>());
- }
- set.add(ob);
- }
- public synchronized static void removeObserver(MessageObserver<?> ob) {
- Class<?> clazz = checkObserver(ob);
- Set<MessageObserver<?>> set = sMap.get(clazz);
- if (set != null) {
- set.remove(ob);
- if (set.isEmpty()) {
- sMap.remove(clazz);
- set = null;
- }
- }
- }
- private static Class<?> checkObserver(MessageObserver<?> ob) {
- Class<?> clazz;
- if (ob == null || (clazz = getGenericClass(ob)) == null) {
- throw new IllegalArgumentException("参数不可为null,或没有使用范型");
- }
- return clazz;
- }
- private static Class<?> getGenericClass(Object obj) {
- try {
- ParameterizedType parameterizedTyped = (ParameterizedType) obj
- .getClass().getGenericInterfaces()[0];
- Type actualType = parameterizedTyped.getActualTypeArguments()[0];
- if (actualType instanceof Class<?>) {
- return (Class<?>) actualType;
- } else {
- Type rawType = ((ParameterizedType) actualType).getRawType();
- if (rawType instanceof Class<?>) {
- return (Class<?>) rawType;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- }
代码很明白了,就说下使用场景和扩展使用:
首先,使用MessageDispatcher前,你要确定自己要监听的对象(大多需要自己设计,不同业务要不同的对象,避免使用通用对象,造成无关的监听器收到消息),这点上,和命令字模型的设计比较,却也是不足之处。
其次,在Android中,很多人比较喜欢在Activity上实现接口,然后MessageDispatcher.addObserver(this),这时就更要注意在onDestory中调用removeObserver方法。
注意,该消息分发器,为了使得可以在子线程中调用,使用了handler,所以按照我目前的水平理解,是可以不分主线程子线程,可以直接调用的。
使用场景
1,、可以在收到服务器消息时,处理完了数据,然后通过该分发器发出消息,如果哪个Activity存在并监听了该消息对象,他将收到具体的消息对象<T>。
2、程序内部,一个界面的操作会影响到其他界面,如列表item点击进入详情,可能需要更新列表item的显示。当然这个可以在onActivityResult中处理,也可以发送广播,甚至你可以使用public static
的方法(见过一个同事这么使用,把我气的。。)。不过想来,我们这个消息分发器,倒是符合广播的部分思想:添加监听(注册广播),分发消息(发送广播)。只是我们的这个消息是完全无序的广播,并没有拦截功能,如果你们项目需要,可以给MessageObserver的onMessage方法添加返回值,并在MessageDispatcher中对MessageObserver添加优先级的管理。
3、其实在程序中,任何需要联动和沟通的地方,都可以使用这种机制。但是如果是业务比较复杂,感觉还是命令字模式比较理想,虽然我不喜欢管理命令字和根据命令字对对象进行解析转换。
最后,MessageDispatcher中getGenericClass方法使用反射,主要为了方便获取监听对象<T>的Class,这个也可以通过在MessageObserver添加一个方法由实现类提供。
不足之处,欢迎指正。
版权声明:本文为博主原创文章,未经博主允许不得转载。