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

Android之观察者/被观察者模式Observer/Observable的更多相关文章

  1. java: 观察者模式:Observable被观察者,Observer观察者

    java: 观察者模式:Observable被观察者,Observer观察者 以房子价格为例,卖房者为被观察者: import java.util.Observable; //被观察者子类化 publ ...

  2. [Android&amp;Java]浅谈设计模式-代码篇:观察者模式Observer

    观察者,就如同一个人,对非常多东西都感兴趣,就好像音乐.电子产品.Game.股票等,这些东西的变化都能引起爱好者们的注意并时刻关注他们.在代码中.我们也有这种一种方式来设计一些好玩的思想来.今天就写个 ...

  3. Java_观察者模式(Observable和Observer) -转

    原文地址: Java_观察者模式(Observable和Observer) 一.观察者模式介绍    在Java中通过Observable类和Observer接口实现了观察者模式.一个Observer ...

  4. 十一、观察者模式(Observable、Observer)

    老板出差了,员工1.员工2..均放羊中.他们请求前台的秘书,当老板回来时通知自己,免得被Boss抓个现行.秘书想了想,说————嗯,这是观察者模式. 当一个对象的改变需要同时改变其它对象,而且它不知道 ...

  5. android中的所谓观察者模式

    生活中我们常认定某些人很有才,但什么是有才呢?明朝的王守仁曾这样解释:才,是所谓天理,应用到物上,便成了才.凡事凡物,只要掌握了所谓科学的方法,并能灵活运用,那么你也可以成为一个有才的人. 观察者模式 ...

  6. C# ~ 从 委托事件 到 观察者模式 - Observer

    委托和事件的部分基础知识可参见 C#/.NET 基础学习 之 [委托-事件] 部分: 参考 [1]. 初识事件 到 自定义事件: [2]. 从类型不安全的委托 到 类型安全的事件: [3]. 函数指针 ...

  7. [设计模式] 19 观察者模式 Observer Pattern

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对观察者模式是这样说的:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.当一个 ...

  8. 我理解设计模式C++实现观察者模式Observer Pattern

    概述: 近期中国股市起起伏伏,当然了起伏就用商机,小明发现商机后果断想入市,买入了中国证券,他想在电脑client上,网页上,手机上,iPad上都能够查看到该证券的实时行情,这样的情况下我们应该怎么设 ...

  9. java设计模式--观察者模式(Observer)

    java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...

随机推荐

  1. mysql锁机制(转载)

    锁是计算机协调多个进程或线程并发访问某一资源的机制 .在数据库中,除传统的 计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许多用户共享的资源.如何保证数据并发访问的一致性.有效性是所 ...

  2. 蓝牙stack bluez学习(1)Stack Architecture

    Bluez支持的features Core Specification 4.2 (GAP, L2CAP, RFCOMM, SDP, GATT) Classic Bluetooth (BR/EDR) B ...

  3. linux三剑客正则表达式

    ^:以...开头,^d,意思是以d开头.例如:ls  -F(-p) | grep " ^d " $:以...结尾,/$,意思是以/结尾.例如:ls -F(-p) | grep &q ...

  4. drf 频率组件 META字典详情

    drf频率组件 什么是频率 控制用户对某个url的请求频率,比如一分钟之内,只能访问三次 自定义频率规则 1.取出访问者ip 2.判断当前ip在不在访问字典中: 不在,则添加进去,返回True; 3. ...

  5. 04 Django模板

    基本概念 作为Web框架,Django提供了模板,用于编写html代码,还可以嵌入模板代码更快更方便的完成页面开发,再通过在视图中渲染模板,将生成最终的html字符串返回给客户端浏览器 模版致力于表达 ...

  6. LeetCode(215) Kth Largest Element in an Array

    题目 Find the kth largest element in an unsorted array. Note that it is the kth largest element in the ...

  7. C与C++接口相互调用

    转载于:http://blog.csdn.net/lincoln_2012/article/details/50801080 项目中经常使用C和C++混合编程,那么,在调用对方接口时,总是不可避免地出 ...

  8. jmeter jdbc各字段的含义

    JDBC采样器各选项的含义如下: 1.Variable Name 其中的Variable Name和上面JDBC Connection Configuration中的Variable Name相同,这 ...

  9. Page-Object思想

    为什么要使用page-object 集中管理元素对象 集中管理一个page内的公共方法 后期维护方便 集中管理元素对象 实现方法: 调用方法: WebElement element = dri ...

  10. Python中的魔术方法详解(双下方法)

    介绍 在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”,中文称『魔术方法』,例如类的初始化方法 __init__ ,Python中所有的魔术方法均在官方文档中 ...