• Android之观察者/被观察者模式Observer/Observable


           Android 本身也是有观察者模式的。虽然项目中很多需要通知数据改变的地方,用了EventBus,但是不得不说这个观察者模式还是很好用的。最近在开发新版本的时候引用了腾讯的IM,之前写直播的时候就用了,当时只在TCChatRoomMgr中注册了消息的监听,因为当时只在直播中用了收发消息,且是单一的聊天室。但是项目的聊天整体接入IM后这个问题就变得棘手了,因为很多界面要接收消息,包括首页,推送,聊天列表,还有直播,这该怎么办呢?模仿腾讯聊天IM的demo,demo中用的就是观察者模式,即只注册一次消息监听(腾讯的文档的代码),然后在所有需要观察的地方注册观察者,根据消息类型进行判断和过滤,问题就迎刃而解了。

          观察者模式:简单来说,就是当对象A对对象B进行进行了类似“订阅”关系,当对象B的数据发生改变时,就要通知对象A进行相应。很简单也很好理解。Android中的观察者需要实现Observer接口,当数据发生改变时,观察者的update()方法就会被调用,被观察者继承Observable类,在数据发生改变时,需要调用setChanged(); this.notifyObservers(obj);这两个方法才可以通知观察者:你想要知道的数据发生了变化了。好了,废话不多说了,下面直接上代码,我都在代码里头做了注释了,各位看官请直接看下面的代码。

    注册观察者:

    public class MessageEvent extends Observable implements TIMMessageListener {
    
    
        private volatile static MessageEvent instance;
    
        private MessageEvent(){
            //注册消息监听器
            TIMManager.getInstance().addMessageListener(this);
        }
    
        public static MessageEvent getInstance(){
            if (instance == null) {
                synchronized (MessageEvent.class) {
                    if (instance == null) {
                        instance = new MessageEvent();
                    }
                }
            }
            return instance;
        }
    
        @Override
        public boolean onNewMessages(List<TIMMessage> list) {
            for (TIMMessage item:list){
                setChanged();
                notifyObservers(item);
            }
            return false;
        }
    
        /**
         * 主动通知新消息
         */
        public void onNewMessage(TIMMessage message){
            setChanged();
            notifyObservers(message);
        }
    
        /**
         * 清理消息监听
         */
        public void clear(){
            instance = null;
        }
    }

      在任何想要接收消息的地方注册观察这就可以了比如ActivityHome:

    public class ActivityHome extends ThinksnsAbscractActivity implements OnChatListener, UnreadMessageListener, OnClickListener, Observer {...
     //在登陆后调用这个
    MessageEvent.getInstance().addObserver(ActivityHome.this);
     @Override
        public void update(Observable observable, Object data) {
            if (observable instanceof MessageEvent) {
                TIMMessage msg = (TIMMessage) data;
                //系统消息,自己发的消息,程序在前台的时候不通知
                if (msg == null || Foreground.get().isForeground() ||
                        (msg.getConversation().getType() != TIMConversationType.Group &&
                                msg.getConversation().getType() != TIMConversationType.C2C) ||
                        msg.isSelf() ||
                        msg.getRecvFlag() == TIMGroupReceiveMessageOpt.ReceiveNotNotify ||
                        (MessageFactory.getMessage(msg) instanceof CustomMessage &&
                                ((CustomMessage) MessageFactory.getMessage(msg)).getType() == CustomMessage.Type.TYPING))
                    return;
                int im_unread_num = PreferenceUtils.getInt(Thinksns.getMy().getUid()+"im_unread_num", 0);
                if (msg.getConversation().getType() == TIMConversationType.C2C) {
                    PreferenceUtils.putInt(Thinksns.getMy().getUid()+"im_unread_num", ++im_unread_num);
                    if (mdNotification != null) {
                        setUnReadUi(mdNotification);
                    } else {
                        fg_my.setUnReadMsg(0);
                    }
                } else if(msg.getConversation().getType() == TIMConversationType.Group && !msg.getConversation().getPeer().contains("@")){
                    PreferenceUtils.putInt(Thinksns.getMy().getUid()+"im_unread_num", ++im_unread_num);
                    if (mdNotification != null) {
                        setUnReadUi(mdNotification);
                    } else {
                        fg_my.setUnReadMsg(0);
                    }
                }
    //            ToastUtils.t("123456789");
            }
        }

    再比如聊天列表页的Presenter里:

    public class ConversationPresenter implements Observer {
    
        private static final String TAG = "ConversationPresenter";
        private ConversationView view;
    
        public ConversationPresenter(ConversationView view){
        
    //注册消息监听 MessageEvent.getInstance().addObserver(this); //注册刷新监听 RefreshEvent.getInstance().addObserver(this); //注册好友关系链监听 FriendshipEvent.getInstance().addObserver(this); //注册群关系监听 GroupEvent.getInstance().addObserver(this); this.view = view; }   //在这个地方处理消息即可 @Override public void update(Observable observable, Object data) { if (observable instanceof MessageEvent){ TIMMessage msg = (TIMMessage) data; view.updateMessage(msg); }else if (observable instanceof FriendshipEvent){ FriendshipEvent.NotifyCmd cmd = (FriendshipEvent.NotifyCmd) data; switch (cmd.type){ case ADD_REQ: case READ_MSG: case ADD: view.updateFriendshipMessage(); break; } }else if (observable instanceof GroupEvent){ GroupEvent.NotifyCmd cmd = (GroupEvent.NotifyCmd) data; switch (cmd.type){ case UPDATE: case ADD: view.updateGroupInfo((TIMGroupCacheInfo) cmd.data); break; case DEL: view.removeConversation((String) cmd.data); break; } }else if (observable instanceof RefreshEvent){ view.refresh(); } } ... }

       使用了这种方法后,上面的困扰就解决了,注册abserver的地方还包括推送,直播页面,注意直播页面的TCChatroomMgr里面收消息一定要进行过滤后判断会话是否为空,因为这里就只收相应聊天室的消息,如果正常操作,退出直播后会退出聊天室,聊天室的消息就不收了,除非遇到闪退的情况(极少),用户还在这个聊天室中,那只能等到聊天解散了,其他对应界面也过滤了直播聊天室的消息。主要是开发起来比较麻烦,张杰磊同学辛苦了!!

       Created by WangXiaotao

  • 相关阅读:
    Spring-12-spring整合Mybatis
    Spring-11-AOP面向切面编程
    jQuery选择器之表单元素选择器
    phpsmarty分配变量
    angular
    ajax 第四步
    ajax第三步
    php+ajax+jq
    二十三种设计模式[4]
    二十三种设计模式[3]
  • 原文地址:https://www.cnblogs.com/widgetbox/p/8392021.html
Copyright © 2020-2023  润新知