android学习之路(三)----RxJava/RxAndroid

本文详细介绍了RxJava的基础概念,包括Observables和Subscribers,通过实例展示了如何创建和订阅Observable,以及如何使用map操作符进行数据变换。此外,还探讨了flatMap()操作符在处理多个Observable组合时的优势,避免了回调地狱。文章强调了错误处理和调度器在Android开发中的重要性,并介绍了如何管理Subscription。最后,简述了Observable的创建和流中间操作符的使用。
摘要由CSDN通过智能技术生成

RxJava学习一、基础篇
一、概述

https://github.com/ReactiveX/RxJava

二、基础
    RxJava最核心的两个东西是Observables(被观察者,事件源)和Subscribers(观察者)。Observables发出一系列事件,Subscribers处理这些事件。这里的事件可以是任何你感兴趣的东西(触摸事件,web接口调用返回的数据)
    一个Observable可以发出零个或者多个事件,直到结束或者出错。每发出一个事件,就会调用它的Subscriber的onNext方法,最后调用Subscriber.onNext()或者Subscriber.onError()结束。
    Rxjava的看起来很像设计模式中的观察者模式,但是有一点明显不同,那就是如果一个Observerble没有任何的的Subscriber,那么这个Observable是不会发出任何事件的。
1. Hello World
创建一个Observable对象很简单,直接调用Observable.create即可

Observable<String> myObservable = Observable.create(
    new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> sub) {
   
            sub.onNext("Hello, world!");
            sub.onCompleted();
        }
    }
);

    这里定义的Observable对象仅仅发出一个Hello World字符串,然后就结束了。接着我们创建一个Subscriber来处理Observable对象发出的字符串。

Subscriber<String> mySubscriber = new Subscriber<String>() {
    @Override
    public void onNext(String s) { System.out.println(s); }
    @Override
    public void onCompleted() { }
    @Override
    public void onError(Throwable e) { }
};

    这里subscriber仅仅就是打印observable发出的字符串。通过subscribe函数就可以将我们定义的myObservable对象和mySubscriber对象关联起来,这样就完成了subscriber对observable的订阅。

myObservable.subscribe(mySubscriber);

    一旦mySubscriber订阅了myObservable,myObservable就是调用mySubscriber对象的onNext和onComplete方法,mySubscriber就会打印出Hello World!
2. 更简洁的代码
        是不是觉得仅仅为了打印一个hello world要写这么多代码太啰嗦?我这里主要是为了展示RxJava背后的原理而采用了这种比较啰嗦的写法,RxJava其实提供了很多便捷的函数来帮助我们减少代码。
        首先来看看如何简化Observable对象的创建过程。RxJava内置了很多简化创建Observable对象的函数,比如Observable.just就是用来创建只发出一个事件就结束的Observable对象,上面创建Observable对象的代码可以简化为一行

Observable<String> myObservable = Observable.just("Hello, world!");

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

Action1<String> onNextAction = new Action1<String>() {
    @Override
    public void call(String s) {
        System.out.println(s);
    }
};

    subscribe方法有一个重载版本,接受三个Action1类型的参数,分别对应OnNext,OnComplete, OnError函数。

myObservable.subscribe(onNextAction, onErrorAction, onCompleteAction);

    这里我们并不关心onError和onComplete,所以只需要第一个参数就可以

myObservable.subscribe(onNextAction);

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

Observable.just("Hello, world!")
    .subscribe(new Action1<String>() {
        @Override
        public void call(String s) {
              System.out.println(s);
        }
    });

使用java8的lambda可以使代码更简洁

Observable.just("Hello, world!")
    .subscribe(s -> System.out.println(s));

3. 变换
    让我们做一些更有趣的事情吧!
    比如我想在hello world中加上我的签名,你可能会想到去修改Observable对象:

Observable.just("Hello, world! -Dan")
    .subscribe(s -> System.out.println(s));

    如果你能够改变Observable对象,这当然是可以的,但是如果你不能修改Observable对象呢?比如Observable对象是第三方库提供的?比如我的Observable对象被多个Subscriber订阅,但是我只想在对某个订阅者做修改呢?
    那么在Subscriber中对事件进行修改怎么样呢?比如下面的代码:

Observable.just("Hello, world!")
    .subscribe(s -> System.out.println(s + " -Dan"));

    这种方式仍然不能让人满意,因为我希望我的Subscribers越轻量越好,因为我有可能会在mainThread中运行subscriber。另外,根据响应式函数编程的概念,    Subscribers更应该做的事情是“响应”,响应Observable发出的事件,而不是去修改。如果我能在某些中间步骤中对“Hello World!”进行变换是不是很酷?
4.操作符(Operators)
    操作符就是为了解决对Observable对象的变换的问题,操作符用于在Observable和最终的Subscriber之间修改Observable发出的事件。RxJava提供了很多很有用的操作符。
    比如map操作符,就是用来把一个事件转换为另一个事件的。

Observable.just("Hello, world!")
  .map(new Func1<String, String>() {
      @Override
      public String call(String s) {
          return s + " -Dan";
      }
  })
.subscribe(s -> System.out.println(s));

使用lambda可以简化为

Observable.just("Hello, world!")
    .map(s -> s + " -Dan")
    .subscribe(s -> System.out.println(s));

    是不是很酷?map()操作符就是用于变换Observable对象的,map操作符返回一个Observable对象,这样就可以实现链式调用,在一个Observable对象上多次使用map操作符,最终将最简洁的数据传递给Subscriber对象。
5.map操作符进阶
    map操作符更有趣的一点是它不必返回Observable对象返回的类型,你可以使用map操作符返回一个发出新的数据类型的observable对象。
    比如上面的例子中,subscriber并不关心返回的字符串,而是想要字符串的hash值

Observable.just("Hello, world!")
    .map(new Func1<String, Integer>() {
        @Override
        public Integer call(String s) {
            return s.hashCode();
        }
    })
    .subscribe(i -> System.out.println(Integer.toString(i)));

    很有趣吧?我们初始的Observable返回的是字符串,最终的Subscriber收到的却是Integer,当然使用lambda可以进一步简化代码:

Observable.just("Hello, world!")
    .map(s -> s.hashCode())
    .subscribe(i -> System.out.println(Integer.toString(i)));

    前面说过,Subscriber做的事情越少越好,我们再增加一个map操作符

Observable.just("Hello, world!")
    .map(s -> s.hashCode())
    .map(i -> Integer.toString(i))
.subscribe(s -> System.out.println(s));

总结:
1.Observable和Subscriber可以做任何事情
    Observable可以是一个数据库查询,Subscriber用来显示查询结果;Observable可以是屏幕上的点击事件,Subscriber用来响应点击事件;Observable可以是一个网络请求,Subscriber用来显示请求结果。
2.Observable和Subscriber是独立于中间的变换过程的。
    在Observable和Subscriber中间可以增减任何数量的map。整个系统是高度可组合的,操作数据是一个很简单的过程。
RxJava学习二、操作符
三、准备工作
    假设我有这样一个方法:
    这个方法根据输入的字符串返回一个网站的url列表(啊哈,搜索引擎)

Observable<List<String>> query(String text); 

    现在我希望构建一个健壮系统,它可以查询字符串并且显示结果。根据上一篇blog的内容,我们可能会写出下面的代码:

query("Hello, world!")
    .subscribe(urls -> {
        for (String url : urls) {
            System.out.println(url);
        }
    });

    这种代码当然是不能容忍的,因为上面的代码使我们丧失了变化数据流的能力。一旦我们想要更改每一个URL,只能在Subscriber中来做。我们竟然没有使用如此酷的map()操作符!!!
    当然,我可以使用map操作符,map的输入是urls列表,处理的时候还是要for each遍历,一样很蛋疼,万幸,还有Observable.from()方法,它接收一个集合作为输入,然后每次输出一个元素给subscriber:

Observable.from("url1", "url2", "url3")
    .subscribe(url -> System.out.println(url));

    我们来把这个方法使用到刚才的场景:

query("Hello, world!")
    .subscribe(urls -> {
        Observable.from(urls)
            .subscribe(url -> System.out.println(url));
    });

    虽然去掉了for each循环,但是代码依然看起来很乱。多个嵌套的subscription不仅看起来很丑,难以修改,更严重的是它会破坏某些我们现在还没有讲到的RxJava的特性。
四、改进
    救星来了,他就是flatMap()。
Observable.flatMap()接收一个Observable的输出作为输入,同时输出另外一个Observable。直接看代码:

query("Hello, world!")
    .flatMap(new Func1<List<String>, Observable<String>>() {
        @Override
        public Observable<String> call(List<String> urls) {
            return Observable.from(urls);
        }
    })
.subscribe(url -> System.out.println(url));

Lambda:

query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .subscribe(url -> System.out.println(url));

    flatMap()是不是看起来很奇怪?为什么它要返回另外一个Observable呢?理解flatMap的关键点在于,flatMap输出的新的Observable正是我们在Subscriber想要接收的。现在Subscriber不再收到List<String>,而是收到一些列单个的字符串,就像Observable.from()的输出一样。
1.还可以更好
flatMap()实在不能更赞了,它可以返回任何它想返回的Observable对象。
比如下面的方法:

// 返回网站的标题,如果404了就返回null
Observable<String> getTitle(String URL);

    接着前面的例子,现在我不想打印URL了,而是要打印收到的每个网站的标题。问题来了,我的方法每次只能传入一个URL,并且返回值不是一个String,而是一个输出String的Observabl对象。使用flatMap()可以简单的解决这个问题。

query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(new Func1<String, Observable<String>>() {
        @Override
        public Observable<String> call(String url) {
            return getTitle(url);
        }
    })
.subscribe(title -> System.out.println(title));

简化:

query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(url -> getTitle(url))
    .subscribe(title -> System.out.println(title));

    是不是感觉很不可思议?我竟然能将多个独立的返回Observable对象的方法组合在一起!帅呆了!
    不止这些,我还将两个API的调用组合到一个链式调用中了。我们可以将任意多个API调用链接起来。大家应该都应该知道同步所有的API调用,然后将所有API调用的回调结果组合成需要展示的数据是一件多么蛋疼的事情。这里我们成功的避免了callback hell(多层嵌套的回调,导致代码难以阅读维护)。现在所有的逻辑都包装成了这种简单的响应式调用。
2.丰富的操作符
    目前为止,我们已经接触了两个操作符,RxJava中还有更多的操作符,那么我们如何使用其他的操作符来改进我们的代码呢?
    getTitle()返回null如果url不存在。我们不想输出”null”,那么我们可以从返回的title列表中过滤掉null值!

query("Hello, world!")
    .flatMap(urls -> Observable.from(urls))
    .flatMap(url -> getTitle(url))
    .filter(title -> title != null)
    .subscribe(title -> System.out.println(title));

    filter()输出和输入相同的元素,并且会过滤掉那些不满足检查条件的。
如果我们只想要最多5个结果:

query("Hello, world!")
    .flatMap(urls ->
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值