RxJava 设计理念 观察者模式 Observable lambdas MD
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相关推荐
- 设计模式之观察者模式(Observable与Observer)
1.什么是观察者模式 简单情形:有A.B.C.D等四个独立的对象,其中B.C.D这三个对象想在A对象发生改变的第一时间知道这种改变,以便做出相应的响应或者对策. 上面的这种情形,就是观察者模式. 当然 ...
- RxJava 源码解析之观察者模式
了解 RxJava 的应该都知道是一个基于事务驱动的库,响应式编程的典范.提到事务驱动和响应就不得不说说,设计模式中观察者模式,已经了解的朋友,可以直接跳过观察者模式的介绍,直接到 RxJava 源码 ...
- 合并RxJava的Observable数据流
本文讨论几种不同方式合并RxJava的Observable数据流. Observable介绍 Observable 序列,或简单称为Observable,表示异步数据流.这些概念遵循基于观察者模式,在 ...
- 数据结构链表例程_如何掌握RxJava例程的四个结构
数据结构链表例程 by Ayusch Jain 通过Ayusch Jain 如何掌握RxJava例程的四个结构 (How to get a grip on the four constructs of ...
- RxJava使用(一)基本使用
前言 RxJava及RxAndroid比较详细的介绍可以参考该文档<给 Android 开发者的 RxJava 详解> 基本介绍 ReactiveX 及 RxJava使用大部分来自和参考& ...
- 大话RxJava:一、初识RxJava与基本运用
转: http://www.jianshu.com/p/856297523728 .subscribeOn(Schedulers.io()) // 指定subscribe()发生在IO线程 ---& ...
- RxJava 和 RxAndroid 一 (基础)
1.RxJava 项目地址 https://github.com/ReactiveX/RxJava 2.RxAndroid 项目地址 https://github.com/ReactiveX/R ...
- RxJava 2.x 入门
之前只大概了解RxJava,并没在实际的项目中实战过,但最近在研究讯飞语音的一个demo的时候发现,他们都在使用mvvm,dagger2,rxjava2.x, 姿态很优雅,很吸引人,心想,卧槽再不尝试 ...
- Java中expecial,RxJava 学习笔记 (一)
作者: 一字马胡 转载标志 [2017-12-13] 更新日志 日期 更新内容 备注 2017-12-13 RxJava学习笔记系列 系列笔记 (一) 2017-12-15 增加系列笔记(二) 201 ...
最新文章
- 路由器和宽带路由器故障汇总!
- 管理信息系统的开发和管理
- sql server 怎么把视图中的数据存到另外一张表中_承上篇,自制插件优化Kep数据存储问题...
- 分布式架构中数据一致性常见的几个问题
- PHP PDO学习(二) exec执行SQL
- JAVA File转Byte[]
- python 等值面 插值_利用numpy/scipy从三维阵列计算等值面
- 【ROS学习笔记】(十二)常用可视化工具
- 用 GitHub 来部署静态网页 ꒰・◡・๑꒱
- 分布式存储系统学习笔记(二)—分布式文件系统(3)—Facebook文件系统(Haystack)
- 容器技术Docker K8s 31 容器服务ACK基础与进阶-弹性伸缩
- Introduction to Computer Networking学习笔记(二十二):TCP拥塞控制-基本方法 AIMD
- Silvaco仿真入门
- 研究鸟类迁徙的目的和意义
- 使用BDE数据库引擎的应用软件出现Insufficient disk space的解决方法
- 利用win10镜像文件安装.net framework 3.5 简单快速
- jQuery贼简单的选项卡切换
- Grafana 教程 - 构建你的第一个仪表盘
- Win32汇编环境配置
- nginx 学习笔记--Nginx正则表达式之匹配操作符
热门文章
- python精通难_Python 为什么入门容易 精通难
- IntelliJ IDEA开发工具安装Scala插件使用
- c语言double字母,C语言double和float 实例分析
- maven 分批打包_maven批量打包,并且显示打包结果
- vue a-sub-menu 添加点击事件报错_Vue+TS 使用的问题(持续更)
- 密歇根安娜堡大学的计算机科学教授,美国密歇根大学安娜堡分校读机械硕士在美国好就业吗?...
- curl php 模拟来源_PHP-Curl模拟HTTPS请求
- android沉浸式 字体,全面解析android沉浸式状态栏
- android系统五大布局,android 五大布局文件
- oracle数据库的select,Oracle数据库--基本的select语句