之前文章介绍了用广播去通知界面更新,这会儿又无法满足我的要求
广播的好处
- 不需要创建消息类型实体便可一对多或是一对一发送
- 系统内置,兼容性好
我现在又为什么不满足于广播?
- 我只能进行简单的收发,时间久了以后,具体的行为无法获知
- 无法传递非序列号对象
- 广播较重
- 耦合度不高不好扩展
我的需求
- 和广播一样,这个消息要一对一发送(或者一对多发送)
- 同时,我不想建大量的消息类型(即使这个类型是个空属性)
- 再者,我需要知道他是什么具体的行为,以便以后回溯
- 我可以传递非序列号的对象
为此我需要打的地基
- 全局状态树Store
- 界面需要观察的行为property
- 界面根据行为进行响应responder
- 行为的分发器DispatchManager
大致的结构
目录结构.png
Show Code!
/**
* Created by Gss on 2018/2/12 0012.
*/
public abstract class BaseStore<T, E extends BaseResponder> {
public final ArrayList<E> observerList = new ArrayList();
private static BaseStore INSTANCE;
public void registerObserver(E t) {
if (checkValid(t))
observerList.add(t);
}
private boolean checkValid(E t) {
return t != null;
}
public void unRegisterObserver(E t) {
if (checkValid(t) && observerList.contains(t))
observerList.remove(t);
}
public abstract void notifyObservers(T t, Object objects);
}
Store目的很简单,将观察者一一添加到集合里
观察者必须实现接口Responder
/**
* Created by Gss on 2018/2/12 0012.
*/
public interface BaseResponder<T> {
void receiveResponse(T t);
String[] bindAction();
}
只有两个方法,需要观察的行为(数组返回),响应receiveResponse(重载后面会有)
/**
* Created by Gss on 2018/2/12 0012.
*/
public abstract class DispatchManager<T extends ActionType> {
public void dispatch(int type) {
dispatch(type, null);
}
public abstract void dispatch(int type, Object data);
}
行为管理器,一个是带参数的方法,一个是不带参数的方法
以上是基类的简易结构,具体实现全在GlobalStore中,如下
/**
* Created by Gss on 2018/2/12 0012.
*/
public class GlobalStore extends BaseStore<Action, Responder> {
private static GlobalStore store;
private Map<Responder, Map<Class, Method>> responderMethod = new HashMap<>();
public static GlobalStore getStore() {
if (store == null) {
store = new GlobalStore();
}
return store;
}
@Override
public void notifyObservers(Action action, Object objects) {
if (objects != null)
action.getAction().setData(objects);
postMessage(action, objects);
}
@Override
public void unRegisterObserver(Responder t) {
super.unRegisterObserver(t);
responderMethod.remove(t);
}
private void postMessage(Action action, Object objects) {
try {
for (Responder responder : observerList) {
for (String s : responder.bindAction())
if (s.equals(action.getAction().getAction())) {
String o = CUtil.getInterfaceType(responder);
if (objects == null || (objects != null && objects.getClass().getSimpleName().equals(o))) {
responder.receiveResponse(objects);
}
//如类型不对,则查找观察者是否有重载的方法
else if (responderMethod.get(responder) == null || responderMethod.get(responder).get(objects.getClass()) == null) {
getMethod(responder, objects);
}
//如类型不对,且map中已存储了map
else if (responderMethod.get(responder).get(objects.getClass()) != null) {
responderMethod.get(responder).get(objects.getClass()).invoke(responder, objects);
} else
responder.receiveResponse(null);
break;
}
}
} catch (Exception e) {
}
}
private boolean getMethod(Responder responder, Object c) {
try {
Method m = responder.getClass().getMethod("receiveResponse", c.getClass());
m.invoke(responder, c);
if (responderMethod.get(responder) == null)
responderMethod.put(responder, new HashMap<Class, Method>());
responderMethod.get(responder).put(c.getClass(), m);
return true;
} catch (Exception e) {
responder.receiveResponse(null);
}
return false;
}
}
方法体含义
- postMessage,遍历观察者集合,从集合中再去获取观察的行为数组进行遍历,如果发出的行为匹配了观察者需要观察的行为,调用responder里的receiveResponse通知界面进行相应操作。
- getMethod,如上responder中没有接收相应参数的方法,查找是否有重载方法,有则调用,并将方法储存在map集合中,以便下一次直接调用
这样管理以后,首先,不存在传输的对象需要序列号的问题;其次,行为完全是开发者自定义的,可以回溯;再者可以对其进行扩展(比如加入严格模式类型不对不调用响应方法之类的)
最后来放出我的使用示例
按钮发生事件.png
两个按钮分别发送申请事件和同意事件
单事件.png
注册单事件
多事件重载5.png
注册多事件,并重载了Interger参数的响应体
发送消息.gif
可以看到,注册了单事件的界面接收不到同意行为,而多事件可以
并且注册了多事件行为的界面本身没有Interger类型的响应体,只是重载了它,一样能成功收到
以上就是简易的通信框架了,如果好用的话,会继续优化
网友评论