用观察者模式仿EventBus
效果
- 在全局任意地方均可发送消息,没类层数限制
- 在任意类注册,可接收到消息
- 关闭Activity或View可以取消订阅
- 可以清晰区分不同任务,指令
/**
* ObMsgBean.CHAT_ADAPTER 为任务类型,区分不同大块任务
* this 1 : Context ,这里传Context只是取了类名,用于记录,不会引起内存泄漏
* this 2 : 回调接口
*/
ObserverTools.getInstance(ObMsgBean.CHAT_ADAPTER).addXNObserver(this, this);
接收消息 【用观察者模式仿EventBus】回调接口
@Override
public void onNext(int type, Object... o) throws Exception {
switch (type) {// 具体指令
case ChatMsgBean.SHOW_LOADING:
// 具体操作
//参数 : o,为数组集合,里面为传过来的参数,至少会有一个参数,为发起命令的类及行号.
break;
}
}
发送消息 在任意位置
// ObMsgBean.CHAT_ADAPTER 为任务类型
// ChatMsgBean.SHOW_LOADING 指令类型
// bmsg.msgID 为传入的参数,动态参数可传多个
ObserverTools.getInstance(ObMsgBean.CHAT_ADAPTER).setMsg(MsgBean.SHOW_LOADING, bmsg.msgID);
解除订阅 删除该任务类型下的所有观察者
ObserverTools.getInstance(ObMsgBean.CHAT_ADAPTER).deleteObservers();
删除该任务类型下的与某个Context相关的观察者
ObserverTools.getInstance(ObMsgBean.CHAT_ADAPTER).deleteContextObservers(context);
删除该任务类型下的指定观察者
ObserverTools.getInstance(ObMsgBean.CHAT_ADAPTER).deleteContextObservers(context);
工具类
/**
* 观察者模式工作类
* 全局通知
* Created by guomeng on 2018/4/20.
*/
@SuppressWarnings("ALL")
public class ObserverTools extends Observable{
private final int taskType;
private ObMsgBean obMsgBean;
/**
* 观察者/map集合
* key : 观察者所属的context 名称
* value : 所在context所有的观察者集合 [ key : 每个观察者所实现的接口hash码
* value : 观察者对象 ]
*/
private ArrayMap> observerMap = new ArrayMap<>();
/**
* 被观察者
*/
private static SparseArray observables = new SparseArray<>();
private XNObserver xnObserver;
/**
* 根据任务类型获取相应实例
*
* @param taskType 任务类型
* @return
*/
public static ObserverTools getInstance(int taskType) {
ObserverTools inst = null;
if (observables.get(taskType) != null) {
inst = observables.get(taskType);
} else {
inst = new ObserverTools(taskType);
observables.put(taskType, inst);
}
return inst;
}private ObserverTools(int taskType) {
this.taskType = taskType;
obMsgBean = new ObMsgBean();
}/**
* 添加观察者对象
*
* @param context所依赖的context
* @param listener 注册的监听对象
* @return this
*/
public ObserverTools addXNObserver(Context context, OnObserverToolListener listener) {
if (listener == null) return null;
if (xnObserver == null)
xnObserver = new XNObserver(this);
xnObserver.setListener(listener);
String key = context.toString();
if (observerMap.containsKey(key)) {
observerMap.get(key).put(listener.hashCode(), xnObserver);
} else {
SparseArray xnObservers = new SparseArray<>();
xnObservers.put(listener.hashCode(), xnObserver);
observerMap.put(key, xnObservers);
}
return this;
}/**
* 删除所有观察者
*/
@Override
public void deleteObservers() {
super.deleteObservers();
observerMap.clear();
observables.remove(taskType);
}/**
* 删除context相关的观察者对象
*
* @param context
*/
public void deleteContextObservers(Context context) {
String key = context.toString();
if (!observerMap.containsKey(key)) {
return;
}
for (int i = 0, nsize = observerMap.get(key).size();
i < nsize;
i++) {
XNObserver xnObserver = observerMap.get(key).valueAt(i);
deleteObserver(xnObserver);
}
observerMap.remove(key);
}/**
* 删除指定观察者
*
* @param listener 实现观察者所在的类
*/
public void disposeObserver(Context context, OnObserverToolListener listener) {
if (listener == null || !observerMap.containsKey(context.toString())) return;
deleteObserver(observerMap.get(context).get(listener.hashCode()));
}public interface OnObserverToolListener {
/**
* 监听者回调
*
* @param type
* @param o
* @throws Exception
*/
void onNext(int type, Object... o) throws Exception;
}/**
* 设置发送消息
*
* @param type 动作类型
* @param parm 参数 可多个
*/
public void setMsg(int type, Object... parm) {
obMsgBean.setType(type);
obMsgBean.setPath("文件 : " + getCurrentFileName() + " 行号 : " + _LINE_());
for (int i = 0;
i < parm.length;
i++)
obMsgBean.setMsg(parm[i]);
setChanged();
notifyObservers(obMsgBean);
}// 当前文件名
private static String getCurrentFileName() {
StackTraceElement traceElement = ((new Exception()).getStackTrace())[3];
return traceElement.getFileName().replace(".java", "");
}// 当前行号
private static int _LINE_() {
StackTraceElement traceElement = ((new Exception()).getStackTrace())[3];
return traceElement.getLineNumber();
}/**
* 观察者内部类
*/
public class XNObserver implements Observer {
ArrayList listeners;
public XNObserver(Observable observable) {
listeners = new ArrayList<>();
observable.addObserver(this);
}@Override
public void update(Observable observable, Object value) {
ObMsgBean obMsgBean = (ObMsgBean) value;
Object[] objects = new Object[obMsgBean.getMsg().size() + 1];
for (int i = 0;
i < obMsgBean.getMsg().size();
i++) {
objects[i] = obMsgBean.getMsg().get(i);
}
objects[obMsgBean.getMsg().size()] = obMsgBean.getPath();
try {
for (int i = 0;
i < listeners.size();
i++) {
listeners.get(i).onNext(obMsgBean.getType(), objects);
}
} catch (Exception e) {
e.printStackTrace();
}
}public void setListener(OnObserverToolListener listener) {
if (!listeners.contains(listener))
listeners.add(listener);
}
}
}
消息实体类和任务类型
/**
* 使用观察者模式时的消息Bean
* Created by boyko on 2017/5/6.
*/
public class ObMsgBean {
/**
* 任务类型 / ******
*//**
* 聊天页面和适配器/聊天列表的交互
*/
public static int CHAT_ADAPTER = 100;
/**
* 设置主题与聊天头像交互
*/
public static int CHAT_AVATAR = 101;
/**
* 触发观察者时,传递的消失类型
*/
int type;
/**
* 发送改消息bean的方法路径
*/
String path;
ArrayList
指令类
public class MsgBean {/**
* 显示头像loading
*/
public static final int SHOW_LOADING = 1000;
/**
* 隐藏头像loading
*/
public static final int HINT_LOADING = 1001;
/**
* 更换主题刷新头像
*/
public static final int REFRESH_AVATAR = 1003;
/**
* 当内容加载完成,listview拉到最底部
*/
public static final int PULL_BOTTOM = 1002;
}
如有不足,请指正.
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- JS中的各种宽高度定义及其应用
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- 涉毒患者(新诗)
- 参保人员因患病来不及到指定的医疗机构就医,能否报销医疗费用()
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。