【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>() {
        @Override
        public void onNext(String s) {
            Log.d("xoliu", "Item: " + s);
        }
     
        @Override
        public void onCompleted() {
            Log.d("xoliu", "Completed!");
        }
     
        @Override
        public void onError(Throwable e) {
            Log.d("xoliu", "Error!");
         }
    };
    

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

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

    Subscriber<String> subscriber = new Subscriber<String>() {
        @Override
        public void onNext(String s) {
            Log.d(tag, "Item: " + s);
        }
     
        @Override
        public void onCompleted() {
            Log.d(tag, "Completed!");
        }
     
        @Override
         public 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>() {
    @Override
    public 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>() {
    @Override
    public void onCompleted() {
        Log.i("xoliu", "onCompleted");
    }

    @Override
    public void onError(Throwable e) {
        Log.i("xoliu", "onError");
    }

    @Override
    public 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>() {
    @Override
    public void call(String s) {
        Log.i("xoliu", "Action1 call : " + s);
    }
};

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

image

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

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

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

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

observable.subscribe(onNextAction, onErrorAction, onCompletedAction);

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PDF Reader Pro 3.0.1.0(pdf阅读器)

PDF Reader Pro是一款功能强大的PDF阅读、注释、填写表单&签名、转换、OCR、合并拆分PDF页面、编辑PDF等软件。 它支持多种颜色的高亮、下划线&#xff0c;可以按需选择&#xff0c;没有空白处可以进行注释&#xff0c;这时候便签是你最佳的选择&#xff0c;不点开时自动隐…

探索锦食送如何通过API集成无代码开发技术提高电商平台和营销系统效率

探索锦食送无代码开发集成技术 随着电子商务和营销系统的快速发展&#xff0c;企业不断寻求更高效和灵活的管理方式。锦食送&#xff0c;作为高端餐饮外卖服务的领先者&#xff0c;通过无代码开发的API集成技术&#xff0c;实现了电商平台和营销系统的高效管理。这种创新的连接…

ROS2串口通讯serial库(适用于humble版本)

要的串口操作的API介绍在这里&#xff1a;serial: serial::Serial Class Reference (wjwwood.io) 但是我们不是直接利用上面这个东西&#xff0c;而是使用的是根据这个改写的一个针对ros2的一个serial库&#xff0c;这个serial库是根据上面这个库改写来的&#xff0c;ros2的库在…

​​​​​​​3分钟实现EG网关串口连接麦格米特PLC

EG网关串口连接麦格米特PLC 前言&#xff1a;麦格米特PLC广泛应于工业控制领域&#xff0c;是一款性能高、稳定性强的PLC设备。此文档将介绍如何使用EG系列网关通过串口连接麦格米特PLC&#xff0c;并添加到EMCP物联网云平台&#xff0c;实现电脑Web页面、手机APP和微信对麦格米…

健康饮酒进家庭,国台酒业与碧桂园服务集团达成战略合作

11月19日&#xff0c;碧桂园服务集团与国台酒业集团战略合作发布会暨“健康饮酒进家庭”项目启动仪式在广州举行。 广东省酒类行业协会创会会长朱思旭&#xff0c;广东省酒类行业协会会长彭洪&#xff0c;碧桂园服务集团总裁徐彬淮&#xff0c;碧桂园服务集团酒类业务总经理、广…

第二证券:万亿巨头!业绩大超预期,但预警在华销售将大幅下滑

当地时间11月21日&#xff0c;美股三大股指收跌。其间&#xff0c;道指跌0.18%&#xff0c;标普500指数跌0.20%&#xff0c;纳斯达克指数跌0.59%。 英伟达盘后发布了第三财季成果&#xff0c;第三财季&#xff0c;英伟达总营收同比增两倍、EPS盈利增近六倍&#xff0c;分别较分…

跑步耳机哪个牌子好?这五款跑步耳机闭眼入也不会错!

作为一个经常跑步运动的人&#xff0c;总感觉运动能够让人暂时远离城市的喧嚣&#xff0c;同时运动也是一种特别好的舒压方法。但跑步的时候如果没有音乐助燃&#xff0c;那是没有灵魂的&#xff0c;这也许就是现代年轻人的矫情吧&#xff0c;我在运动的时候经常会佩戴骨传导耳…

【报错记录】解决使用Kotlin写的SpringBoot项目使用Aspect切面无法生效的问题

前言 为了能在SpringBoot使用Kotlin&#xff0c;真的是各种坑都彩礼一遍&#xff0c;这次遇到的问题是Aspect无法对Kotlin代码生效。我这里的使用场景是使用切面切Controller中的方法&#xff0c;用来对接口进行一些初始化和收尾工作。 Aspect在Controller类还是Java代码的时…

排序算法--冒泡排序

实现逻辑 ① 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 ②对每一对相邻元素作同样的工作&#xff0c;从开始第一对到结尾的最后一对。在这一点&#xff0c;最后的元素应该会是最大的数。 ③针对所有的元素重复以上的步骤&#xff0c;除了最后一个。 ④…

最护眼的灯是白炽灯吗?专业的护眼台灯推荐

以前科技发展落后&#xff0c;晚上需要照明时也只有白炽灯可以使用&#xff0c;这也是迫不得已的事情。白炽灯最大的优点就是成本便宜&#xff0c;而且显色比较接近自然光。不过缺点也有着不少&#xff0c;例如&#xff1a;光线分布不均匀、刺眼、能耗高、寿命短等等。 如今时…

Vatee万腾的数字化掌舵:Vatee科技解决方案的全面引领

随着数字化时代的到来&#xff0c;Vatee万腾凭借其卓越的科技实力和全面的解决方案&#xff0c;成功地在数字化探索的航程中掌舵引领。 首先&#xff0c;Vatee万腾以其强大的数字化科技实力成为行业的引领者。vatee万腾不仅在人工智能、大数据分析、云计算等前沿领域取得了显著…

8-cgi fastcgi wsgi uwsgi uWSGI 分别是什么?如何自定制上下文管理器、Python是值传递还是引用传递

1 cgi fastcgi wsgi uwsgi uWSGI 分别是什么&#xff1f; 2 如何自定制上下文管理器 3 Python是值传递还是引用传递 1 cgi fastcgi wsgi uwsgi uWSGI 分别是什么&#xff1f; # CGI:通用网关接口&#xff08;Common Gateway Interface/CGI&#xff09;,CGI描述了服务器&#xf…

CAS方式实现单点登录SSO

1. CAS介绍 CAS&#xff08;Central Authentication Service&#xff09;中心认证服务 下面这张图来自官网&#xff0c;清晰简单的介绍了CAS的继续交互过程 2. CAS具体实现 首先需要分别搭建CAS-server和CAS-client服务&#xff0c; 这两个服务分别在2台机器上&#xff0c;…

使用CSS渲染不同形状

本文只是用来记录自己遇到的图形 1.图形一 2.图形二 3.图形三 4.图形四 5.图形五

校招社招,在线测评测什么内容?

校招社招&#xff0c;在线测评测什么内容&#xff1f; 通常来说&#xff0c;包括的范围大概是&#xff1a; 认知能力、职业性格、岗位胜任力、心理健康。 在线测评&#xff0c;通常排在网申之后&#xff0c;投递简历后&#xff0c;如果简历过了&#xff0c;那么在线测评就少不…

使用Echarts.js绘制中国地图

使用Echarts.js绘制中国地图 一、页面效果 二、功能描述 ​ 1、展示中国所有省份&#xff0c;包括南海诸岛&#xff0c;确保领土完整&#xff0c;中国领土神圣且不可侵犯。 ​ 2、每个省份根据对应数据的不同渲染不同的颜色&#xff0c;根据数据从小到大&#xff0c;对应底部…

定时器的使用

目录 前言 正文 1.方法 schedule(TimerTask task, Date time) 的测试 &#xff08;1&#xff09;执行任务的时间晚于当前时间(在未来执行)的效果 &#xff08;2&#xff09;线程TimerThread不销毁的原因 &#xff08;3&#xff09;使用 public void cancel() 方法实现 T…

为何内存不够用?微服务改造启动多个Spring Boot的陷阱与解决方案

在生产环境中我们会遇到一些问题&#xff0c;此文主要记录并复盘一下当时项目中的实际问题及解决过程。 背景简述 最初系统上线后都比较正常风平浪静的。在系统运行了一段时间后&#xff0c;业务量上升后&#xff0c;生产上发现java应用内存占用过高&#xff0c;服务器总共64…

「Verilog学习笔记」含有无关项的序列检测

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 timescale 1ns/1ns module sequence_detect(input clk,input rst_n,input a,output reg match);reg [8:0] a_tem ; always (posedge clk or negedge rst_n) begin if (~rs…

【giszz笔记】产品设计标准流程【7】

&#xff08;续上回&#xff09; 今天来讨论下产品设计标准流程中&#xff0c;交互设计和视觉设计的内容。 想参考之前文章的&#xff0c;我把链接给到这里。 【giszz笔记】产品设计标准流程【6】-CSDN博客 【giszz笔记】产品设计标准流程【5】-CSDN博客 【giszz笔记】产品…