RxJava初探

本文深入介绍了响应式编程的概念和观察者模式,重点讲解了RxJava的基本原理、优缺点及核心操作符如Map、FlatMap、Buffer和Interval的使用。同时,通过实例展示了RxJava在线程切换、心跳/指标收集等场景的应用,帮助读者理解并掌握RxJava在Android开发中的实践。

目录

目录

一、预备知识

1.响应式编程

2.观察者模式(发布订阅模式)

二、RxJava

1.RxJava是什么?

2.RxJava的优缺点

3.基本原理

三、基本操作符

Map

FlatMap

Buffer

Interval

四、应用场景

demo源码

参考文献

相关链接




一、预备知识

1.响应式编程

响应式编程(reactive programming)是一种基于数据流(data stream)和变化传递(propagation of change)的声明式(declarative)的编程范式。

响应式编程常见的各种listener,callback,UI。

2.观察者模式(发布订阅模式)

二、RxJava

1.RxJava是什么?

RxJava是一个遵循观察者设计模式,封装后的异步操作库。

2.RxJava的优缺点

优点:

1.流式处理,代码简洁;

2.功能强大,各种操作符丰富,错误处理;

3.异步调度。

缺点:

1.上手困难,与传统编程方式差异很大;

2.服务端开发多同步操作,应用场景有限,Android编程更广泛。

3.基本原理

RxJava四要素

一个基本使用的例子

    Observable.create((ObservableOnSubscribe<Integer>) e -> {
            e.onNext(1);
            e.onNext(2);
            e.onNext(3);
            e.onComplete();
        }).subscribe(new Observer<>() {
            @Override
            public void onSubscribe(Disposable disposable) {
                System.out.println("onSubscribe...");
            }

            @Override
            public void onNext(Integer integer) {
                System.out.println("onNext..." + integer);
            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("onError..." + throwable.getMessage());
            }

            @Override
            public void onComplete() {
                System.out.println("onComplete...");
            }
        });

输出:
onSubscribe...
onNext...1
onNext...2
onNext...3
onComplete...

线程转换

subscribeOn(Schedulers.single())  产生事件的线程

observeOn(Schedulers.single())    消费线程

IO

最常见的调度器之一。用于IO相关操作。比如网络请求和文件操作。IO 调度器背后由线程池支撑。无限大小多线程池。

Computation

这个是计算工作默认的调度器,它与I/O操作无关。它也是许多RxJava方法的默认调度器:buffer(),debounce(),delay(),interval(),sample(),skip()

Single

此款调度器非常简单,由一个线程支持。所以无论有多少个observables,都将只运行在这个线程上。也可将其认为是主线程的一个替代

Trampoline

当我们想在当前线程执行一个任务时,并不是立即,我们可以用.trampoline()将它入队。这个调度器将会处理它的队列并且按序运行队列中每一个任务。它是repeat()retry()方法默认的调度器。

Executor Scheduler

更像是一种自定义的IO调度器。我们可以通过制定线程池的大小来创建一个自定义的线程池。适用于observables的数量对于IO调度器太多的场景使用,使用如下:

三、基本操作符

Map

FlatMap

它可以把一个发射器 Observable 通过某种方法转换为多个 Observables,然后再把这些分散的 Observables装进一个单一的发射器 Observable。但有个需要注意的是,flatMap 并不能保证事件的顺序,如果需要保证,需要用到我们下面要讲的 ConcatMap

Observable.create((ObservableOnSubscribe<Integer>) e -> {
            e.onNext(1);
            e.onNext(2);
            e.onNext(3);
        }).flatMap((Function<Integer, ObservableSource<String>>) integer -> {
            List<String> list = new ArrayList<>();
            for (int i = 0; i < integer; i++) {
                list.add("I am value " + integer);
            }
            return Observable.fromIterable(list);
        }).subscribe(flatElement -> System.out.println("subscribe-" + flatElement));

输出:
subscribe-I am value 1
subscribe-I am value 2
subscribe-I am value 2
subscribe-I am value 3
subscribe-I am value 3
subscribe-I am value 3

Buffer

buffer 操作符接受两个参数,buffer(count,skip),作用是将 Observable 中的数据按 skip (步长) 分成最大不超过 count 的 buffer ,然后生成一个 Observable

Observable.just(1, 2, 3, 4, 5)
            .buffer(3, 2)
            .subscribe(integers -> {
                System.out.println("buffer size : " + integers.size() + ", buffer value :");
                for (Integer i : integers) {
                    System.out.print(i + ",");
                }
                System.out.println();
            });


输出:
buffer size : 3, buffer value :
1,2,3,
buffer size : 3, buffer value :
3,4,5,
buffer size : 1, buffer value :
5,

Interval

interval 操作符用于间隔时间执行某个操作,其接受三个参数,分别是第一次发送延迟,间隔时间,时间单位。

Observable.interval(0, 1, TimeUnit.SECONDS, Schedulers.trampoline())
            .observeOn(Schedulers.trampoline())
            .subscribe(aLong -> System.out.println("interval :" + aLong + " at " + LocalDateTime.now()));

输出:
interval :0 at 2021-06-06T23:28:52.988059
interval :1 at 2021-06-06T23:28:53.965217
interval :2 at 2021-06-06T23:28:54.964462
interval :3 at 2021-06-06T23:28:55.964698
interval :4 at 2021-06-06T23:28:56.965941
interval :5 at 2021-06-06T23:28:57.964382
interval :6 at 2021-06-06T23:28:58.969673
interval :7 at 2021-06-06T23:28:59.966106

四、应用场景

1.线程切换

@Test
    public void testThreadControl() {
        Function<Integer, Integer> function = integer -> {
            log.info("currentThread: {}, data:{}", Thread.currentThread().getName(), integer);
            return integer;
        };

        Supplier<Integer> supplier = () -> {
            Thread.sleep(3000);
            return 1;
        };

        ExecutorService executor = Executors.newFixedThreadPool(1);
        PublishSubject.fromSupplier(supplier)
                      .subscribeOn(Schedulers.trampoline())//主线程发送数据
                      .map(function)//new 1 线程接收数据
                      .observeOn(Schedulers.single())//切换single 线程接收数据
                      .map(function)//single 线程接收数据
                      .observeOn(Schedulers.from(executor))//自定义线程池
                      .map(function)//自定义线程池 接收数据
                      .subscribe(System.out::println);
    }

日志:
13:57:34.911 [main] INFO RxJavaTest - currentThread: main, data:1
13:57:34.925 [RxSingleScheduler-1] INFO RxJavaTest - currentThread: RxSingleScheduler-1, data:1

13:57:34.929 [pool-2-thread-1] INFO RxJavaTest - currentThread: pool-2-thread-1, data:1
1

2.心跳/指标收集

@SpringBootTest(classes = Application.class)
public class RxJavaTest {

    private Subject<Long> collectPipeline;

    @Before
    public void init() {
        this.collectPipeline = PublishSubject.create();
        this.collectPipeline.observeOn(Schedulers.trampoline()).subscribeOn(Schedulers.trampoline())
                            .buffer(1, TimeUnit.SECONDS, Schedulers.computation(), 5, HashSet::new, false)
                            .filter(CollectionUtils::isNotEmpty).subscribe(this::batchSaveUserLastActiveTime);
    }

    public void emitActiveUserId(Long userId) {
        collectPipeline.onNext(userId);
        System.out.println(String.format("online userId: %s", userId));
    }

    private void batchSaveUserLastActiveTime(Set<Long> idSet) {
        System.out.println(
                String.format("save user last active time, size:%s, ids:%s", idSet.size(), idSet));
    }

    @Test
    public void testBuffer() throws InterruptedException {
        List<Long> idList = Arrays.asList(1000L, 1001L, 1000L, 1002L, 1003L, 1004L, 1005L, 1006L);
        for (Long id : idList) {
            emitActiveUserId(id);
        }
        Thread.sleep(2000);
    }
}


日志:
online userId: 1000
online userId: 1001
online userId: 1000
online userId: 1002
online userId: 1003
save user last active time, size:5, ids:[1000, 1001, 1002, 1003, 1004]
online userId: 1004
online userId: 1005
online userId: 1006
save user last active time, size:2, ids:[1005, 1006]

使用concat和first做缓存

使用timer做定时操作。当有“x秒后执行y操作”类似的需求的时候,想到使用timer

使用interval做周期性操作。当有“每隔xx秒后执行yy操作”类似的需求的时候,想到使用interval

Hystrix使用RxJava简洁的window API来构建metric.

demo源码

demo源码地址

参考文献

rxjava异步框架源码解析

RxJava调度器

相关链接

RxJava国内外文档/库/项目总结

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值