【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,一经查实,立即删除!

相关文章

怎么判断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进行体…

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

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

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

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

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引入 <!--…

C语言入门——第十七课

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

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

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

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报错 联合注入 …

21款奔驰GLS450升级23P驾驶辅助 提升安全出行

辅助驾驶越来越多的被大家所青睐&#xff01;为了提升驾驶安全性和舒适便捷性奔驰改装原厂半自动驾驶23P辅助系统 23P智能辅助驾驶系统还是很有必要的&#xff0c;因为在跑高速的时候可以使用23P智能驾驶的自动保持车速&#xff0c;保持车距&#xff0c;车道自动居中行驶以及自…

CRM商机管理软件:构建客户为中心的管理理念

企业为什么选择CRM商机管理软件&#xff1f;1.CRM软件能够帮助企业建立以客户为中心的管理理念&#xff1b;2.CRM商机管理软件全面直观的展示客户数据&#xff1b;3.市场人员可以制订个性化的营销策略&#xff1b;4.移动应用为外出的销售带来的便利。 1.构建客户为中心的管理理…

C++实现KNN和K-Means

学校机器学习课程的实验课要求实现KNN和K-Means&#xff1a; &#xff08;平时没听课&#xff09;临时去查了一下KNN和K-Means是啥&#xff0c;然后自己用C写了小例子&#xff0c;想着写都写了那就把代码贴出来吧。 顺便再聊聊自己对于这俩算法的理解。 下面是文心一言的回答…

十年诉讼,迈瑞真的赢了吗?

迁延十年&#xff0c;迈瑞与科曼的知识产权纠纷案究竟要如何解读&#xff1f; 发端于2013年&#xff0c;两家国内医疗器械行业知名公司间的专利互诉官司&#xff0c;成为全行业最具代表性的案例。但这一案例本质并不复杂&#xff1a;不过商业利益之争。 要在烈度不断抬升的市…

项目管理PMP6.0-五大过程组、十大知识领域、四十九个过程(记忆码:7664363734)

项目管理PMP6.0-五大过程组、十大知识领域、四十九个过程&#xff08;记忆码&#xff1a;7664363734&#xff09; 项目经理的影响力范围三者关系图&#xff08;五大过程组、十大知识领域、四十九个过程&#xff09;五大过程组十大知识领域十大知识领域之间联系 四十九个过程&am…

如何通过提升客户体验带来更大的增长、更好的客户留存率?

客户期望的转变 在一个日益数字化的世界里&#xff0c;有必要采取以客户为中心的思维方式。因为客户与企业互动的方式有很多是在数字空间发生的&#xff0c;客户的需求和模式已经转变。 这种情况已经酝酿了几年&#xff0c;但在2020年才打开闸门。随着疫情的爆发&#xff0c;企…

FTX的前世今生:崛起、辉煌与崩塌

FTX&#xff0c;一度被誉为加密货币领域的明星交易所&#xff0c;其快速的崛起和令人瞩目的崩塌吸引了全球的关注。让我们回顾一下FTX的前世今生&#xff0c;了解其短暂的辉煌和骤然的崩塌。 1. 崛起&#xff1a; FTX的创始人山姆班克曼-弗里德在加密货币领域具有深厚的背景和…

Linux主机间的相互免秘钥

主机间的相互免秘钥 1.生成密钥 ssh-keygen -t rsa -P -f ~/.ssh/id_rsa运行以上命令后会在 ~/.ssh/ 目录下生成一对密钥对。 2.拷贝公钥 把自己的公钥传递给对方主机即可&#xff0c;这个公钥文件必须放在对方主机的~/.ssh/authorized_keys 文件中。 ssh-copy-id -i ~/.s…

智能座舱架构与芯片 - (2) 架构篇

一、定义 1.1 智能座舱定义 按照百度百科的定义&#xff0c;智能座舱&#xff08;intelligent cabin&#xff09;旨在集成多种IT和人工智能技术&#xff0c;打造全新的车内一体化数字平台&#xff0c;为驾驶员提供智能体验&#xff0c;促进行车安全。目前国内外已经有很多研究…