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. python入门:最基本的用户登录用户登录,三次错误机会

    #!/usr/bin/env python # -*- coding:utf-8 -*- #用户登录,三次错误机会 """ 导入getpass,给x赋值为1,while真 ...

  2. 使用kickstart + pxe 部署无人值守安装

    1.作为中小公司的运维,经常会遇到一些机械式的重复工作,例如:有时公司同时上线几十甚至上百台服务器,而且需要我们在短时间内完成系统安装. 常规的安装系统方法: 光盘安装系统:一个服务器DVD内置光驱百 ...

  3. gulp的安装和使用

    安装nodejs -> 全局安装gulp -> 项目安装gulp以及gulp插件 -> 配置gulpfile.js -> 运行任务 1.去nodejs官网安装nodejs 2. ...

  4. Java求字符串中出现次数最多的字符

    Java求字符串中出现次数最多的字符  [尊重原创,转载请注明出处]http://blog.csdn.net/guyuealian/article/details/51933611      Java ...

  5. 20181210(os,os.path,subprocess,configparser,shutil)

    1.os模块 os表示操作系统,该模块主要处理与操作系统相关的操作.最常用的是文件操作:打开,读取,删除,复制,重命名. 重点掌握增删改查的函数操作. import os# 获取当前执行文件所在文件夹 ...

  6. perl-tips-1

    .pm 应该保存 Perl Module,也就是 Perl 模块.例如 Socket.pm.pl 应该保存 Perl Library,也就是 Perl 库文件.例如 perldb.pl.plx 应该保 ...

  7. 制作iso文件

     genisoimage -o fusionstor-yi-2017-03-08.iso(镜像名称) -v -cache-inodes -joliet-long -R -J -T -V ZS  -c  ...

  8. SQL_1_简介

    了解一门语言,还是应该从名字开始.SQL中的S即Structured(结构),L即Language(语言),Q即Query(查询),但不仅仅只是查询,还可以建立数据库,添加和删除数据,对数据作联合,当 ...

  9. 打造一款属于自己的web服务器——从简单开始

    距离开篇已经过了很久,期间完善了一下之前的版本,目前已经能够完好运行,基本上该有的功能都有了,此外将原来的测试程序改为示例项目,新项目只需按照示例项目结构实现controller和view即可,详情见 ...

  10. JavaScript 将当地时间转换成其它时区

    毫无疑问,用JavaScript脚本可以通过直接查看用户的时钟,方便地在网页上显示本地时间. 但是,如果你想显示不同地区的时间—--例如,如果你的本部在别的国家,你想查看“本国”时间而非当地时间,又该 ...