美文网首页
用观察者模式仿EventBus

用观察者模式仿EventBus

作者: Boyko | 来源:发表于2018-05-10 11:51 被阅读0次

    效果

    1. 在全局任意地方均可发送消息,没类层数限制
    2. 在任意类注册,可接收到消息
    3. 关闭Activity或View可以取消订阅
    4. 可以清晰区分不同任务,指令

    使用方法

    注册

    在任意类进行注册

    /**
     * ObMsgBean.CHAT_ADAPTER 为任务类型,区分不同大块任务
     * this 1 : Context ,这里传Context只是取了类名,用于记录,不会引起内存泄漏
     * this 2 : 回调接口
     */
    ObserverTools.getInstance(ObMsgBean.CHAT_ADAPTER).addXNObserver(this, this);
    
    接收消息

    回调接口

      @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<String, SparseArray<XNObserver>> observerMap = new ArrayMap<>();
        /**
         * 被观察者
         */
        private static SparseArray<ObserverTools> 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<XNObserver> 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<OnObserverToolListener> 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<Object> list = new ArrayList();
    
        public int getType() {
            return type;
        }
    
        public void setType(int type) {
            cleanData();
            this.type = type;
        }
    
        private void cleanData() {
            type = 0;
            list.clear();
        }
    
        public String getPath() {
            return path;
        }
    
        public void setPath(String path) {
            this.path = path;
        }
    
        public void setMsg(Object msg) {
            list.add(msg);
        }
    
        public ArrayList<Object> getMsg() {
            return list;
        }
    }
    

    指令类

    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;
    
    }
    

    如有不足,请指正.

    相关文章

      网友评论

          本文标题:用观察者模式仿EventBus

          本文链接:https://www.haomeiwen.com/subject/pkrzrftx.html