Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

RxJava 设计理念 观察者模式 Observable lambdas MD
demo地址


目录

目录
常用库
首先写一个最简单的观察者模式
我们再对比下用 rx 写的观察者模式
简化代码
介绍一个操作符:map
对于 map 的更多用法
对 rx 设计理念的理解

常用库

implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
implementation 'io.reactivex.rxjava2:rxjava:2.x.x'implementation 'com.jakewharton.rxrelay2:rxrelay:2.0.0'implementation "com.github.akarnokd:rxjava2-extensions:0.16.0"implementation "com.squareup.retrofit2:retrofit:2.0.0"
implementation "com.squareup.retrofit2:converter-gson:2.0.0"
implementation "com.squareup.okhttp3:okhttp:3.7.0"
implementation "com.squareup.okhttp3:okhttp-urlconnection:3.0.1"
implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'implementation 'top.zibin:Luban:1.1.8'
implementation 'com.github.tbruyelle:rxpermissions:0.10.2'
implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'

首先写一个最简单的观察者模式

interface Watcher {  void update(String str);
}  

interface Watched {  void addWatcher(Watcher watcher);  void removeWatcher(Watcher watcher);  void notifyWatchers(String str);
}  

class ConcreteWatcher implements Watcher {  @Override  public void update(String str) {  Log.i("bqt", "观察者收到被观察者的消息:" + str);  }
}  

class ConcreteWatched implements Watched {  private List<Watcher> list = new ArrayList<>();  @Override  public void addWatcher(Watcher watcher) {  if (list.contains(watcher)) {  Log.i("bqt", "失败,被观察者已经注册过此观察者");  } else {  Log.i("bqt", "成功,被观察者成功注册了此观察者");  list.add(watcher);  }  }  @Override  public void removeWatcher(Watcher watcher) {  if (list.contains(watcher)) {  boolean success = list.remove(watcher);  Log.i("bqt", "此观察者解除注册观察者结果:" + (success ? "成功" : "失败"));  } else {  Log.i("bqt", "失败,此观察者并未注册到被观察者");  }  }  @Override  public void notifyWatchers(String str) {  for (Watcher watcher : list) {  watcher.update(str);  }  }
}  

演示案例:

private Watcher watcher;
private Watched watched;
...
watcher = new ConcreteWatcher();
watched = new ConcreteWatched();
...
watched.addWatcher(watcher);
watched.notifyWatchers("救命啊");
watched.removeWatcher(watcher);  

我们再对比下用 rx 写的观察者模式

首先,我们创建一个基本的被观察者Observable:

Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {  @Override  public void subscribe(ObservableEmitter<String> emitter) {  emitter.onNext("救命啊-------isDisposed=" + emitter.isDisposed());//false  if (new Random().nextBoolean()) emitter.onComplete(); //发送onComplete  else emitter.onError(new Throwable("发送onError")); //发送onComplete或onError事件后就取消注册了  Log.i("bqt", "调用 onComplete 或 onError 后 isDisposed=" + emitter.isDisposed());//true  }
});  

接着我们创建Observer来消费这个数据:

Observer<String> observer = new Observer<String>() {  @Override  public void onSubscribe(Disposable d) {  Log.i("bqt", "成功订阅-------isDisposed=" + d.isDisposed());//false  }  @Override  public void onNext(String s) {  Log.i("bqt", "【观察者接收到了事件】onNext:" + s);  }  @Override  public void onError(Throwable e) {  Log.i("bqt", "对Error事件作出响应:" + e.getMessage());  }  @Override  public void onComplete() {  Log.i("bqt", "对Complete事件作出响应");  }
};  

现在我们已经有了Observable和Observer,那么就可以通过subscribe()函数把两者关联起来了:

observable.subscribe(observer);//被观察者注册观察者  

简化代码

在以下这个例子中,Observable.just()发送一个消息然后完成,功能类似上面的代码。

Observable<String> observable = Observable.just("救命啊");  

接下来,让我们处理Observer不必要的样板代码。如果我们不关心onSubscribe、onCompleted、onError的话,那么可以使用一个更简单的类来定义onNext()要完成什么功能:

new Consumer<String>() {  @Override  public void accept(String s) throws Exception {  Log.i("bqt", "【观察者收到被观察者的消息】onNext:" + s);  }
};  

可以用Consumer或Action来定义Observer的每一个部分,Observable.subscribe()函数能够处理一到四个参数,分别表示onNext(),onError()和onComplete()和onSubscribe函数。

public final Disposable subscribe(Consumer<? super T> onNext)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete)  

因此,上述代码可简化为:

Observable.just("救命啊").subscribe(new Consumer<String>() {  @Override  public void accept(String s) throws Exception {  Log.i("bqt", "【观察者收到被观察者的消息】onNext:" + s);  }
});  

使用lambdas表达式去掉丑陋的Consumer代码:

Observable.just("救命啊")  .subscribe(s -> Log.i("bqt", "【观察者收到被观察者的消息】onNext:" + s));  

不仅如此,因为 just 方法可以接受多个不同类型的数据,所以我们可以对一系列数据同时进行处理:

Observable.just("救命啊", 1, true, 1.5f)  .subscribe(s -> "【观察者收到被观察者的消息】onNext:" + s));  

介绍一个操作符:map

让我们来点刺激的。假如我想把我的签名拼接到"Hello, world!"的输出中,一个可行的办法是改变Observable:

Observable.just("Hello, world! -包青天").subscribe(s -> System.out.println(s));  

这么做存在两个问题:

  • 当你有权限控制Observable时这么做是可行的,但不能保证每次都可以这样,因为如果你使用的是别人的函数库呢?
  • 如果项目中在多个地方使用此Observable,但只在某一个地方需要增加签名,这时怎么办?

你可能会想到,我们可以单独修改此Subscriber:

Observable.just("Hello, world!")  .subscribe(s -> System.out.println(s + " -包青天"));  

用这个解决方案的话,虽然上面的问题解决了,但同样也存在一个重要的问题:

因为我希望Subscribers应尽可能的轻量级,而不要耦合任何的业务逻辑(比如对Observable发送的数据做再处理)。
从更概念化的层面上讲,Subscribers只是用于被动响应的,而不是主动发送或处理消息的。

接下来我们将介绍如何解决消息转换的难题:使用Operators。
Operators在消息发送者Observable(被观察者)和消息消费者Subscriber(观察者)之间起到操纵消息的作用。RxJava拥有大量的opetators,map()这个operator可以用来将已被发送的消息转换成另外一种形式:

Observable.just("Hello, world!")  .map(new Function<String, String>() {  @Override  public String apply(String s) throws Exception {  return s + " -包青天";  }  })  .subscribe(s -> System.out.println(s));  

使用lambdas表达式后:

Observable.just("Hello, world!")  .map(s -> s + " -包青天")  .subscribe(s -> System.out.println(s));  

很酷吧?这里的map()操作符本质上是一个用于转换消息对象的Observable。我们可以级联调用任意多个的map()函数,一层一层地将初始消息转换成Subscriber需要的数据形式。

对于 map 的更多用法

map()函数有趣的一点是:它不需要发送和原始的Observable一样的数据类型。
假如我的Subscriber不想直接输出原始的数据,而是想输出原始数据的hash值,可以这样写:

Observable.just("Hello, world!")  .map(s -> s.hashCode())  .subscribe(i -> System.out.println(Integer.toString(i)));  

这样,我们的原始输入是字符串,但Subscriber最终收到的是Integer类型。

正如说过的,我们希望Subscriber做尽量少的工作,所以我们还可以把hash值转换成字符串的操作移动到一个新的map()函数中:

Observable.just("Hello, world!")  .map(s -> s.hashCode())  .map(i -> Integer.toString(i))  .subscribe(s -> System.out.println(s));  

给力吧!我们的Observable和Subscriber完全还是原来的代码,我们只是根据不同的需求在中间添加了一些变换的操作。

类似的案例:

Observable.just(System.currentTimeMillis())  .map(time -> time + 1000 * 60 * 60)//改变时间的值  .map(time -> new SimpleDateFormat("HH:mm:ss", Locale.getDefault()).format(new Date(time)))  .subscribe(string -> Log.i("bqt", string));  

对 rx 设计理念的理解

上面只是一个简单的例子,但其中有几个思想你需要理解:

第一:通过上面的Observable和Subscriber,你能完成任何你想做的事情,也就是说这是一个可以处理任何事情的通用的框架。

  • 你的Observable可以是一个数据库查询,Subscriber获得查询结果然后将其显示在屏幕上。
  • 你的Observable可以是屏幕上的一个点击,Subscriber响应该事件。
  • 你的Observable可以从网络上读取一个字节流,Subscriber将其写入本地磁盘中。

第二:Observable和Subscriber与它们之间的一系列转换步骤是相互独立的。

  • 我们可以在消息发送者Observable和消息消费者Subscriber之间加入任意个你想要的map()函数,这个系统是高度可组合的,它很容易对数据进行操纵。
  • 只要operators符合输入输出的数据类型,那么我可以得到一个无穷尽的调用链。

结合这两个概念,你可以看到一个有极大潜能的系统。并且我们还只是介绍了RxJava中的其中一个operator,实际上RxJava中还定义了大量的其他的operators,在你深入了解后,你会深深感叹:卧槽,你牛逼。

2018-9-18

转载于:https://www.cnblogs.com/baiqiantao/p/463e135c55afb336e7d199ee7a9658bd.html

RxJava 设计理念 观察者模式 Observable lambdas MD相关推荐

  1. 设计模式之观察者模式(Observable与Observer)

    1.什么是观察者模式 简单情形:有A.B.C.D等四个独立的对象,其中B.C.D这三个对象想在A对象发生改变的第一时间知道这种改变,以便做出相应的响应或者对策. 上面的这种情形,就是观察者模式. 当然 ...

  2. RxJava 源码解析之观察者模式

    了解 RxJava 的应该都知道是一个基于事务驱动的库,响应式编程的典范.提到事务驱动和响应就不得不说说,设计模式中观察者模式,已经了解的朋友,可以直接跳过观察者模式的介绍,直接到 RxJava 源码 ...

  3. 合并RxJava的Observable数据流

    本文讨论几种不同方式合并RxJava的Observable数据流. Observable介绍 Observable 序列,或简单称为Observable,表示异步数据流.这些概念遵循基于观察者模式,在 ...

  4. 数据结构链表例程_如何掌握RxJava例程的四个结构

    数据结构链表例程 by Ayusch Jain 通过Ayusch Jain 如何掌握RxJava例程的四个结构 (How to get a grip on the four constructs of ...

  5. RxJava使用(一)基本使用

    前言 RxJava及RxAndroid比较详细的介绍可以参考该文档<给 Android 开发者的 RxJava 详解> 基本介绍 ReactiveX 及 RxJava使用大部分来自和参考& ...

  6. 大话RxJava:一、初识RxJava与基本运用

    转:  http://www.jianshu.com/p/856297523728 .subscribeOn(Schedulers.io()) // 指定subscribe()发生在IO线程 ---& ...

  7. RxJava 和 RxAndroid 一 (基础)

    1.RxJava 项目地址 https://github.com/ReactiveX/RxJava 2.RxAndroid 项目地址    https://github.com/ReactiveX/R ...

  8. RxJava 2.x 入门

    之前只大概了解RxJava,并没在实际的项目中实战过,但最近在研究讯飞语音的一个demo的时候发现,他们都在使用mvvm,dagger2,rxjava2.x, 姿态很优雅,很吸引人,心想,卧槽再不尝试 ...

  9. Java中expecial,RxJava 学习笔记 (一)

    作者: 一字马胡 转载标志 [2017-12-13] 更新日志 日期 更新内容 备注 2017-12-13 RxJava学习笔记系列 系列笔记 (一) 2017-12-15 增加系列笔记(二) 201 ...

最新文章

  1. 路由器和宽带路由器故障汇总!
  2. 管理信息系统的开发和管理
  3. sql server 怎么把视图中的数据存到另外一张表中_承上篇,自制插件优化Kep数据存储问题...
  4. 分布式架构中数据一致性常见的几个问题
  5. PHP PDO学习(二) exec执行SQL
  6. JAVA File转Byte[]
  7. python 等值面 插值_利用numpy/scipy从三维阵列计算等值面
  8. 【ROS学习笔记】(十二)常用可视化工具
  9. 用 GitHub 来部署静态网页 ꒰・◡・๑꒱
  10. 分布式存储系统学习笔记(二)—分布式文件系统(3)—Facebook文件系统(Haystack)
  11. 容器技术Docker K8s 31 容器服务ACK基础与进阶-弹性伸缩
  12. Introduction to Computer Networking学习笔记(二十二):TCP拥塞控制-基本方法 AIMD
  13. Silvaco仿真入门
  14. 研究鸟类迁徙的目的和意义
  15. 使用BDE数据库引擎的应用软件出现Insufficient disk space的解决方法
  16. 利用win10镜像文件安装.net framework 3.5 简单快速
  17. jQuery贼简单的选项卡切换
  18. Grafana 教程 - 构建你的第一个仪表盘
  19. Win32汇编环境配置
  20. nginx 学习笔记--Nginx正则表达式之匹配操作符

热门文章

  1. python精通难_Python 为什么入门容易 精通难
  2. IntelliJ IDEA开发工具安装Scala插件使用
  3. c语言double字母,C语言double和float 实例分析
  4. maven 分批打包_maven批量打包,并且显示打包结果
  5. vue a-sub-menu 添加点击事件报错_Vue+TS 使用的问题(持续更)
  6. 密歇根安娜堡大学的计算机科学教授,美国密歇根大学安娜堡分校读机械硕士在美国好就业吗?...
  7. curl php 模拟来源_PHP-Curl模拟HTTPS请求
  8. android沉浸式 字体,全面解析android沉浸式状态栏
  9. android系统五大布局,android 五大布局文件
  10. oracle数据库的select,Oracle数据库--基本的select语句