【Rxjava详解】(一)观察者模式的拓展

文章目录

    • RxJava引入
      • 扩展的观察者模式
      • RxJava的观察者模式
      • 基本实现
    • RxJava入门示例
      • Action

RxJava引入

在介绍RxJava之前先说一下Rx。全称是Reactive Extensions,直译过来就是响应式扩展

Rx基于观察者模式,它是一种编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流ReactiveX.io给的定义是,Rx是一个使用可观察数据流进行异步编程的编程接口,ReactiveX结合了观察者模式、迭代器模式和函数式编程的精华。Rx已经渗透到了各个语言中,有RxJavaRxJSRxSwift等等

总结一下RxJava的作用就是:异步

但是RxJava的好处是简洁。异步操作很关键的一点是程序的简洁性,因为在调度过程比较复杂的情况下,异步代码经常会既难写也难被读懂。 Android的AsyncTaskHandler其实都是为了让异步代码更加简洁。虽然RxJava的优势也是简洁,但它的简洁的与众不同之处在于,随着程序逻辑变得越来越复杂,它依然能够保持简洁。

扩展的观察者模式

RxJava的异步实现,是通过一种扩展的观察者模式来实现的。

观察者模式面向的需求是:A对象(观察者)对B对象(被观察者)的某种变化高度敏感,需要在B变化的一瞬间做出反应。

观察者不需要时刻盯着被观察者(例如A不需要每过2ms就检查一次B的状态),而是采用注册(Register)或者称为订阅(Subscribe)的方式,告诉被观察者:我需要你的某某状态,你要在它变化的时候通知我。

通用的观察者模式:

image

RxJava作为一个工具库,使用的就是通用形式的观察者模式。

RxJava的观察者模式

RxJava的基本概念:

  • Observable(可观察者,即被观察者):产生事件,例如去饭店吃饭的顾客。
  • Observer(观察者):接收事件,并给出响应动作,例如去饭店吃饭的厨房,会接受事件,并给出相应。
  • subscribe()(订阅):连接被观察者与观察者,例如去饭店吃饭的服务员。
    ObservableObserver通过subscribe() 方法实现订阅关系,从而Observable可以在需要的时候发出事件来通知Observer
  • Event(事件):被观察者与观察者沟通的载体,例如顾客点的菜。

与传统观察者模式不同,RxJava的事件回调方法除了普通事件onNext()(相当于onClick()/onEvent())之外,还定义了两个特殊的事件:onCompleted()onError():

但是RxJava与传统的观察者设计模式有一点明显不同,那就是如果一个Observerble没有任何的的Subscriber,那么这个Observable是不会发出任何事件的。

  • onCompleted(): 事件队列完结。

    RxJava不仅把每个事件单独处理,还会把它们看做一个队列。RxJava规定,当不会再有新的onNext()发出时,需要触发onCompleted() 方法作为标志。

  • onError(): 事件队列异常。
    在事件处理过程中出异常时,onError()会被触发,同时队列自动终止,不允许再有事件发出。

  • 在一个正确运行的事件序列中, onCompleted()onError()有且只有一个,并且是事件序列中的最后一个。需要注意的是onCompleted()onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。

RxJava的观察者模式大致如下图:

image

基本实现

基于上面的概念, RxJava的基本实现主要有三点:

  • 创建Observable

    Observable即被观察者,它决定什么时候触发事件以及触发怎样的事件RxJava使用Observable.create()方法来创建一个Observable,并为它定义事件触发规则

  • 创建Observer

    观察者,它决定事件触发的时候将有怎样的行为

    RxJava中的Observer接口的实现方式:

    Observer<String> observer = new Observer<String>() {@Overridepublic void onNext(String s) {Log.d("xoliu", "Item: " + s);}@Overridepublic void onCompleted() {Log.d("xoliu", "Completed!");}@Overridepublic void onError(Throwable e) {Log.d("xoliu", "Error!");}
    };
    

    RxJava还内置了一个实现了Observer的抽象类:Subscriber

    SubscriberObserver接口进行了一些扩展,但他们的基本使用方式是完全一样的。

    Subscriber<String> subscriber = new Subscriber<String>() {@Overridepublic void onNext(String s) {Log.d(tag, "Item: " + s);}@Overridepublic void onCompleted() {Log.d(tag, "Completed!");}@Overridepublic void onError(Throwable e) {Log.d(tag, "Error!");}
    };
    

    不仅基本使用方式一样,实质上,在RxJavasubscribe()过程中,Observer也总是会先被转换成一个Subscriber再使用。所以如果你只想使用基本功能,选择ObserverSubscriber是完全一样的。它们的区别对于使用者来说主要有两点:

    • onStart(): 这是Subscriber增加的方法。它会在subscribe()刚开始而事件还未发送之前被调用,可以用于做一些准备工作,例如数据的清零或重置。这是一个可选方法,默认情况下它的实现为空。需要注意的是,如果对准备工作的线程有要求(例如弹出一个显示进度的对话框,这必须在主线程执行), onStart()就不适用了,因为它总是在subscribe() 所发生的线程被调用,而不能指定线程。要在指定的线程来做准备工作,可以使用doOnSubscribe()方法,具体可以在后面的文中看到。

    • unsubscribe(): 这是Subscriber所实现的另一个接口Subscription的方法,用于取消订阅。在这个方法被调用后,Subscriber 将不再接收事件。一般在这个方法调用前,可以使用isUnsubscribed()先判断一下状态。

      unsubscribe()这个方法很重要,因为在subscribe()之后,Observable会持有 Subscriber的引用,这个引用如果不能及时被释放,将有内存泄露的风险。所以最好保持一个原则:要在不再使用的时候尽快在合适的地方(例如onPause()、onStop()等方法中)调用unsubscribe()来解除引用关系,以避免内存泄露的发生。

  • 调用subscribe()方法(订阅)

    创建了一个ObservableObserver之后,再用subscribe()方法将它们联结起来:

    observable.subscribe(observer);  
    // 或者:
    observable.subscribe(subscriber);
    

    subscribe()这个方法有点怪:它看起来是observalbe订阅了observer/subscriber而不是observer/subscriber订阅了observalbe,这让人读起来有点别扭

RxJava入门示例

一个Observable可以发出零个或者多个事件,知道事件结束或者出错。每发出一个事件,就会调用它的Subscriber的onNext()方法,最后调用Subscriber.onComplete()或者Subscriber.onError()结束。

// 创建被观察者、数据源
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {@Overridepublic void call(Subscriber<? super String> subscriber) {// 这里传入了一个 OnSubscribe 对象作为参数。OnSubscribe 会被存储在返回的 Observable 对象中,它的作用相当于一个计划表,当 Observable      // 被订阅的时候,OnSubscribe 的 call() 方法会自动被调用,事件序列就会依照设定依次触发(观察者Subscriber 将会被调用三次 onNext() 和一次 onCompleted()// 这样,由被观察者调用了观察者的回调方法,就实现了由被观察者向观察者的事件传递,即观察者模式。subscriber.onNext("Hello ");subscriber.onNext("World !");subscriber.onCompleted();//结束}
});
// 创建观察者
Subscriber<String> subscriber = new Subscriber<String>() {@Overridepublic void onCompleted() {Log.i("xoliu", "onCompleted");}@Overridepublic void onError(Throwable e) {Log.i("xoliu", "onError");}@Overridepublic void onNext(String s) {Log.i("xoliu", "onNext : " + s);}
};
// 订阅
observable.subscribe(subscriber);

一旦subscriber订阅了observableobservable就会调用subscriber对象的onNextonComplete方法,subscriber就会打印出Hello World.

subscriber(Subscriber subscriber)做了3件事:

  • 调用Subscriber.onStart()是一个准备方法。
  • 调用Observable对象中的onSubscribe.call(Subscriber)。在这里,事件发送的逻辑开始运行。从这也可以看出,在RxJava中,Observable 并不是在创建的时候就立即开始发送事件,而是在它被订阅的时候,即当subscribe()方法执行的时候。
  • 将传入的Subscriber作为Subscription返回。这是为了方便unsubscribe().

整个过程中对象间的关系如下图:

image

RxJava内置了很多简化创建Observable对象的函数,

  • Observable.just()用来创建只发出一个事件就结束的Observable对象
Observable<String> observable = Observable.just("Fuck u ", "World !");

接下来看看如何简化Subscriber,上面的例子中,我们其实并不关心onComplete()onError,我们只需要在onNext的时候做一些处理,这时候就可以使用Action1类。

Action

什么是Action
Action是RxJava 的一个接口,常用的有Action0Action1。虽然Action0Action1在API中使用最广泛,但RxJava是提供了多个ActionX形式的接口(例如Action2, Action3)的,它们可以被用以包装不同的无返回值的方法。

  • Action0: 它只有一个方法 call(),这个方法是无参无返回值的;由于 onCompleted() 方法也是无参无返回值的,因此 Action0 可以被当成一个包装对象,将 onCompleted() 的内容打包起来将自己作为一个参数传入 subscribe() 以实现不完整定义的回调。
  • Ation1:它同样只有一个方法 call(T param),这个方法也无返回值,但有一个参数;与 Action0 同理,由于 onNext(T obj)onError(Throwable error) 也是单参数无返回值的,因此 Action1 可以将 onNext(obj)onError(error) 打包起来传入 subscribe() 以实现不完整定义的回调
Action1<String> action1 = new Action1<String>() {@Overridepublic void call(String s) {Log.i("xoliu", "Action1 call : " + s);}
};

Observable.subscribe()方法有一个重载版本,接受三个Action1类型的参数

image

所以上面的代码最终可以写成这样:

Observable.just("Hello ", "World !").subscribe(new Action1<String>() {@Overridepublic void call(String s) {Log.i("xoliu", "call : " + s);}
});

这里顺便多提一些subscribe()的多个Action参数:

Action1<String> onNextAction = new Action1<String>() {// onNext()@Overridepublic void call(String s) {Log.d(tag, s);}
};
Action1<Throwable> onErrorAction = new Action1<Throwable>() {// onError()@Overridepublic void call(Throwable throwable) {// Error handling}
};
Action0 onCompletedAction = new Action0() {// onCompleted()@Overridepublic void call() {Log.d(tag, "completed");}
};observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/158225.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp:如何实现点击图片可以全屏展示预览

这个需要使用uniapp中的api&#xff1a;uni.previewImage&#xff0c;使用方法如下 1、html <template><view><image src"图片路径" click"preview"></image></view> </template> 2、JavaScript <script> e…

pyhive的离线安装及使用示例

pyhive离线安装 pyhive下载离线安装包 下载方式一:直接把jieba包下载到/download/pip/目录下 pip download -d /download/pip/ pyhive[hive_pure_sasl]下载方式二:建一个requirement.txt文件里面一行一行写需要的包,/usr/local/download/pip/是下载目录 pip download -d /d…

怎么判断list是否为null

List<Entity> baseMess new ArrayList<>(); baseMess motiveService.getBaseMessage(machine.get(i),preDate,nowDate); System.out.println("获取Size"baseMess.size()); baseMess.removeIf(Objects::isNull); System.out.println("获取Size"…

Cannot read property ‘pickAlgorithm‘ of null

Cannot read property pickAlgorithm of null 报错显示 node 和 npm的版本号不对应 查看版本号 node -v npm -v node的版本对应 Previous Releases | Node.js (nodejs.org) 我们需要改成对应的mpm版本号 npm install npm6.14.12 -g nodejs与npm版本对应关系以及使用nvm管理n…

『亚马逊云科技产品测评』活动征文|利用EC2云服务器快速部署一个SpringBoot项目

&#xff08;授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道&#xff09; 1. 前言 本文主要是对亚马逊云科技的EC2进行体…

前端字符串方法汇总

1、length属性 const sss lengthconsole.log(字符串长度是, sss.length) 2、chartAt() charAt()和charCodeAt()方法都可以通过索引来获取指定位置的值&#xff1a; charAt() 方法获取到的是指定位置的字符&#xff1b;charCodeAt()方法获取的是指定位置字符的Unicode值。 …

Java基于B/S架构,包括PC后台管理端、APP移动端、可视化数据大屏的智慧工地源码

智慧工地管理平台充分运用数字化技术&#xff0c;聚焦施工现场岗位一线&#xff0c;依托物联网、互联网、AI等技术&#xff0c;围绕施工现场管理的人、机、料、法、环五大维度&#xff0c;以及施工过程管理的进度、质量、安全三大体系为基础应用&#xff0c;实现全面高效的工程…

【算法-哈希表5】看似哈希,实则双指针。

今天&#xff0c;带来哈希表和双指针相关算法的讲解。文中不足错漏之处望请斧正&#xff01; 理论基础点这里 四数之和 题意简化 四数之和&#xff0c;去重版&#xff1a;找不重复的四元组 四元组四个元素下标不同, 和为target四元组不重复 由于输出四元组的顺序没有限制, …

MySQL之BETWEEN AND包含范围查询总结

一、时间范围 查询参数格式与数据库类型相对应时&#xff0c;between and包含头尾&#xff0c;否则依情况 当数据库字段中存储的是yyyy-MM-dd格式&#xff0c;即date类型&#xff1a; 用between and查询&#xff0c; 参数yyyy-MM-dd格式时&#xff0c;包含头尾&#xff0c;相当…

Java虚拟机(JVM)的调优技巧和实战2

JVM是Java应用程序的运行环境&#xff0c;它负责管理Java应用程序的内存分配、垃圾收集等重要任务。在JVM的默认设置下&#xff0c;可能存在一些性能问题&#xff0c;因此需要进行调优。在本次分享中&#xff0c;作者将介绍一些实用的JVM实战调优技巧&#xff0c;以提高Java应用…

JVM 监控命令详解

文章目录 JDK 中与常用命令行工具jpsjstatjinfojmap导出 dump 文件查看堆内存信息 jstack JVM 可视化分析工具 JDK 中与常用命令行工具 jps 查看当前服务器正在执行的 Java 进程 $> jps 7584 Application 16433 AdminApplication 14209 Jps 5813 Bootstrap 5575 TestApplic…

HTML+CSS+ElementUI搭建个人博客静态页面展示(纯前端)

网站演示 搭建过程 技术选取:HTML/CSS VUE2 ElementUI(Version - 2.15.14)编程软件:VSCode 环境配置与搭建 安装指令 1. 先确保你的电脑已经安装好了npm和node npm -vnode -v2. ElementUI下载&#xff0c;推荐使用 npm 的方式安装 npm i element-ui -S3. CDN引入 <!--…

根据list集合进行分页

/*** param pageInfo* param caseInfoList*/ public static Map<String, Object> resultPageList(PageInfo pageInfo, List<?> caseInfoList) {Map<String, Object> resultMap new HashMap<>();int pageSize 0;int count 0;//刚开始的页面为第一页pa…

C语言入门——第十七课

一、二分查询 1.概念 二分查询又被称为二分查找&#xff0c;是一种在有序数组或序列中快速查找到对应元素的一种方法。每次查找范围缩小至原来的一半。 ①前提条件 数组和列表必须有序&#xff0c;否则无法进行二分查找。 ②初始化 确定查找数组和列表的左边界&#xff0…

C盘变红怎么办?一个快速解决C盘快满的方法

前情提要 通常解决C盘快满的方法是&#xff1a; 找到C盘—右击选择“属性”—选择“详细信息”—卸载不常用的软件或者清除临时文件 缺点&#xff1a;成效甚微 今日重点 1.背景知识&#xff1a;微信是我们日常工作和生活都离不开的工具&#xff0c;我们每天使用微信会产生大量…

java网络编程Socket output is already shutdown

在java的网络编程中使用TCP协议在Client端和Server端循环收发消息时&#xff0c;如果用的是BufferedReader和BufferedWriter&#xff0c;出现Client端只能发送一次消息&#xff0c;当发送第二次消息时&#xff0c;Server端已经关闭的情况&#xff0c;具体报错为&#xff1a;Soc…

C 语言共用体(Union)

C 语言共用体(Union) 在本教程中&#xff0c;您将学习C语言编程中的共用体。更具体地说&#xff0c;如何创建共用体&#xff08;联合体&#xff09;&#xff0c;访问其成员以及了解共用体与组织之间的差异。共用体又被称为联合体, 和结构体同属于C语言数据类型中的结构类型。 …

Mendix与Java组件的完美结合实践

前言 在技术驱动的今天&#xff0c;应用开发的速度和质量已经成为企业竞争力的决定性因素。Mendix&#xff0c;作为一款领先的低代码开发平台&#xff0c;已经为全球数千家企业提供了快速、高效的开发解决方案。但在某些情况下&#xff0c;企业的特定需求可能超出了Mendix的标…

sqli-labs(3)

11. 看到登录框直接or 11 在hackerabar中我们可以看到这里是post传递的数据&#xff0c;在get中用--来注释后面的内容 因为get中#是用来指导浏览器动作的&#xff0c;--代表注释是空格&#xff0c;所以这里用# 之后就和get的一样了 1 order by 2 # order by 3报错 联合注入 …