使用观察者模式完美解决activity与fragment通信问题

概述

通常来说,解决activity和fragment通信的问题。我们都是采用如下几种方式,
handler,广播,EvnetBus,接口等。那么有没有一种更好的方式来实现呢,最近项目一只在使用Rx,这里参照了一下Rx的设计来解决如上问题。先来说说常用的几种方式。

handler方式

这是一种最不好的初级方式,在fragment中调用activity中的handler发送信息,activity处理信息。缺点也十分明显,耦合性极强,并且获取不了activity的反馈,总之体验十分不好。

广播

这是一种另类的玩法,个人感觉大材小用了。广播适用于一对多且接收者不明确的情况下,
而且广播传播的信息需要实现序列化借口,总之是一种耗费性能的方式。

EvnetBus

EvnetBus作为一款事件总线存在,可以用于Action的传递,但是这种方式的缺点有:是用反射(对性能有影响),EvnetBus发送者和接受者分离严重,不好维护,且不可以获取activity反馈,也不是十分理想。

接口

之前处理这类问题一直也是适应这种方式,总体来讲还是很不错。但是也有缺点,当项目大了的时候,就需要定义很多的接口,这时候就容易混淆,不好维护。

新大陆

总结一下Rx的设计思路,Rx和设计模式中的观察者十分类似。activity和fragment通信,实质上就是所谓事件的传递和响应,只是这个事件是一个特殊的事件,就是可以执行的方法(js中function也可以是参数),那么如果activity需要监听fragment的事件,只需要观察其相应事件即可,fragment同理。

如果对观察者不熟悉的可以看一下:这就是观察者模式

Observable

public interface ObservableInterface<T, P, R> {

  /**
   * 根据名称注册观察者
   */
  void registerObserver(String name, T observer);

  /**
   * 根据名称反注册观察者
   */
  void removeObserver(String name);

  /**
   * 根据观察者反注册
   */
  void removeObserver(T observer);

  /**
   * 根据名称和观察者反注册
   */
  void removeObserver(String name, T observer);

  /**
   * 根据名称获取观察者
   */
  Set<T> getObserver(String name);

  /**
   * 清除观察者
   */
  void clear();

  /**
   * 通知观察者
   *
   * @param name 名称
   * @param p 参数
   * @return 返回值
   */

  R notify(String name, P... p);
}

Observer

public interface Function<Result, Param> {

  Result function(Param... data);
}

这里的Observer就是一个方法的抽象,包含 参数 和 返回值。在Activity和Fragment中传递的就是Fuction,在需要监听的地方注册事件,在适当的地方触发事件。下面看一下Observable的具体实现

ObservableManager

public class ObservableManager<Param, Result>
    implements ObservableInterface<Function, Param, Result> {

  private static final String TAG = "ObservableManager";
  private HashMap<String, Set<Function>> _mapping;
  private final Object _lockObj = new Object();
  private static ObservableManager _instance;

  public ObservableManager() {
    this._mapping = new HashMap<>();
  }

  public static ObservableManager newInstance() {
    if (_instance == null) _instance = new ObservableManager();
    return _instance;
  }

  @Override public void registerObserver(String name, Function observer) {
    synchronized (_lockObj) {
      Set<Function> observers;
      if (!_mapping.containsKey(name)) {
        observers = new HashSet<>();
        _mapping.put(name, observers);
      } else {
        observers = _mapping.get(name);
      }
      observers.add(observer);
    }
  }

  @Override public void removeObserver(String name) {
    synchronized (_lockObj) {
      _mapping.remove(name);
    }
  }

  @Override public void removeObserver(Function observer) {
    synchronized (_lockObj) {
      for (String key : _mapping.keySet()) {
        Set<Function> observers = _mapping.get(key);
        observers.remove(observer);
      }
    }
  }

  @Override public void removeObserver(String name, Function observer) {
    synchronized (_lockObj) {
      if (_mapping.containsKey(name)) {
        Set<Function> observers = _mapping.get(name);
        observers.remove(observer);
      }
    }
  }

  @Override public Set<Function> getObserver(String name) {
    Set<Function> observers = null;
    synchronized (_lockObj) {
      if (_mapping.containsKey(name)) {
        observers = _mapping.get(name);
      }
    }
    return observers;
  }

  @Override public void clear() {
    synchronized (_lockObj) {
      _mapping.clear();
    }
  }

  public Result notify(String name, Param... param) {
    synchronized (_lockObj) {
      if (_mapping.containsKey(name)) {
        Set<Function> observers = _mapping.get(name);
        for (Function o : observers) {
          return (Result) o.function(param);
        }
      }
      return null;
    }
  }
}

这里才用了一个HashMap来存储所有Observer集合,触发事件后就轮询集合循序之行,这就是观察者其中之一的缺点,一个Observer可能阻塞,影响其他执行。

使用

Activity中注册Function事件,Fragment中出发Function事件,执行的到结果,反之亦然。

// 注册事件,Activity实现Function接口
ObservableManager.newInstance().registerObserver(FUNCTION_WITH_PARAM_AND_RESULT, this);
//触发事件,并获得返回值
Object notify = ObservableManager.newInstance()
        .notify(MainActivity.FUNCTION_WITH_PARAM_AND_RESULT, "我是fragment传到activity的参数1", fragmentActivity,
            fragmentResult);
//事件执行,实现于Function接口
@Override public Object function(Object[] data) {
   String text = activityResult.getText().toString() + "\n\n\n";

   activityResult.setText(text + "fragment调用我成功,获取到参数 :" + Arrays.asList(data));

   return "我是activity的返回结果";
 }

最终效果:

activityfragment
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容