RxJava用法入门及操作符讲解,简单易懂

在看本文之前,假如你已经看过一些Rxjava的介绍,有了大致了解,但是仍然看不懂RxJava代码,并且对它的使用场景心存疑惑,那么本篇文章是适合你的。

RxJava的学习还是有一定门槛的,难度在于理解它的思维方式,和各种操作符的用处。本篇文章从最基础的RxJava示例来讲解,说明RxJava的基本使用及基础操作符的作用。

注:本篇文章的RxJava,指的是RxJava1,其他版本的操作符和用法可能会有一些变化。

本篇目录

  • 前言:RxJava的一些介绍
  • 得到Observable被观察者对象
  • 得到Observer观察者对象
  • 实现观察订阅
  • RxJava实例讲解
  • Retrofit+RxJava用法示例

前言:RxJava的一些介绍

首先要了解,RxJava是基于观察者模式的,简而言之就是观察者订阅了被观察者,然后被观察者产生的数据变化会通知到观察者,观察者从而作出反应。这里就不多做讲解了。在Android里,观察者模式的场景非常多,比如OnClickListener,比如EventBus等。

那么RxJava能干嘛呢?对入门来说,只要是“拿数据,做处理”这样的流程,都可以用RxJava实现。比如Retrofit网络请求经常搭配RxJava来实现。甚至打印一个字符串列表也可以用RxJava实现,只要你不嫌它大材小用。

在RxJava里,观察者用Observer类或者Subscriber类表示,其中后者是前者的实现类,两者用法基本相同。观察者就是处理数据的角色。
而被观察者用Observable类表示,它是产生数据的角色。

一、首先我们来看下如何得到一个Observable对象,也就是被观察者。

得到Observable有下面几种常用方法:

1.Observable.create(xxx)

这里的xxx为Observable.OnSubscribe对象,即订阅事件发生的时候,用于产生数据的对象。

Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                subscriber.onNext("1.....");
                subscriber.onNext("2.....");
                subscriber.onNext("3.....");
                subscriber.onCompleted();
            }
        });

这个数据源产生的数据,就是三个字符串。

2.Observable.from(yyy)

这里的yyy为数组,集合,或者Future对象

List<String> list=new ArrayList<>();
        list.add("11111");
        list.add("22222");
        list.add("33333");
        list.add("444444444");
Observable observable = Observable.from(list);

同样,这个observable对象所能产生的数据也是四个字符串。

3.Observable.just(x,y,z…)

这里的x,y,z…可以是不同类型的数据。

Observable observable = Observable.just(1,2,3,4,5);

上例这个observable能产生1~5的数字。

二、再来看下如何得到一个观察者对象(Subscriber或者Observer)

Subscriber<String> subscriber = new Subscriber<String>() {
    @Override
    public void onCompleted() {
       Log.d("test", "onCompleted");
    }

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

    @Override
    public void onNext(String s) {
        Log.d("test", "onNext:"+s);
    }
};
Observer<String> observer = new Observer<String>() {
    @Override
    public void onCompleted() {
        Log.d("test", "onCompleted");
    }

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

    @Override
    public void onNext(String s) {
        Log.d("test", "onNext:"+s);
    }
};

上面实现了两种观察者对象,Subscriber和Observer对象所要实现的抽象方法是一样的。
这里我们定义此观察者处理的数据类型为String类型。实际可根据需求来。按上面这样得到的观察者对象,能做什么呢?
onNext(String s):用于处理数据。
onCompleted():数据全部处理完成,会走到这里。
onError(Throwable e):数据处理过程出错,会走这里。

三、实现订阅

上面两步已经得到了被观察者和观察者对象,还差一步,就是确立订阅关系:

observable.subscribe(observer);

或者

observable.subscribe(subscriber);

看上面这两行代码会发现,在RxJava里,订阅关系是被观察者(observable)订阅了观察者(observer),与我们平时的理解相反。
其实Rxjava这么写只是为了链式调用比较方便。真正subscribe()方法的源码实现里,仍然是观察者订阅了被观察者。

实际使用中,还可以通过observable.subscribe(new Action0(){…})这样的方式,即不必定义观察者,而是通过Action0这样的类包装得到。下面会有例子。

四、实例解析

把上面三步用链式调用连接起来,完整的例子如下:
例1:打印字符串基本示例

Observable.create(new Observable.OnSubscribe<String>() {
    @Override
    public void call(Subscriber<? super String> subscriber) {
        subscriber.onNext("str1");
        subscriber.onNext("str2");
        subscriber.onNext("str3");
        subscriber.onCompleted();
    }
}).subscribe(new Subscriber<String>() {
    @Override
    public void onCompleted() {
        Log.d("test", "onCompleted");
    }

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

    @Override
    public void onNext(String s) {
        Log.d("test", "onNext:"+s);
    }
});

运行结果:

D/test: onNext:str1
D/test: onNext:str2
D/test: onNext:str3
D/test: onCompleted

这个例子实现的功能很简单,就是依次打印三个字符串,完成后再打印"onCompleted"。如果流程中出了错误,则会打印"onError"。

例2:流程前后加入额外处理的示例
subscribe()方法传入的可以是Subscriber对象,Observer对象,或者Action1对象。

List<String> list=new ArrayList<>();
list.add("11111");
list.add("22222");
list.add("33333");
list.add("44444");
Observable.from(list)
        .subscribe(new Action1<String>() {
    @Override
    public void call(String s) {
        Log.d("test", "call:"+s);
    }
});

同样功能很简单,就是依次打印四个字符串。

如果想在打印前后做一些额外处理,怎么办呢?可以像下面这样改:

List<String> list=new ArrayList<>();
list.add("11111");
list.add("22222");
list.add("33333");
list.add("44444");
Observable.from(list)
	//处理前的操作
    .doOnSubscribe(new Action0() {
        @Override
        public void call() {
            Log.d("test", "doOnSubscribe");
        }
    })
    //处理完成后的操作
    .doOnCompleted(new Action0() {
        @Override
        public void call() {
            Log.d("test", "doOnCompleted");
        }
    })
    //正式处理的操作
    .subscribe(new Action1<String>() {
		@Override
		public void call(String s) {
			Log.d("test", "call:"+s);
		}
	});

上面加上了doOnSubscribe和doOnCompleted操作,用于在正式处理前后进行额外处理。
类似地,在流程发生错误,或者终止等时机,RxJava都有对应的方法用于处理。

还可以看到,上面出现了Action0和Action1两个类,它们有什么区别呢?
Action0的call()不会传入参数,而Action1的call()会传入一个参数。类似地还有Action2,Action3,Action4等等。

运行结果:

D/test: doOnSubscribe
D/test: call:11111
D/test: call:22222
D/test: call:33333
D/test: call:44444
D/test: doOnCompleted

例3:数据处理前的筛选变换

Observable.just(1,2,3,4,5)
          .filter(new Func1<Integer, Boolean>() {
              @Override
              public Boolean call(Integer integer) {
                  return integer%2==0;
              }
          })
          .subscribe(integer -> Log.d("test", "call:"+integer));

这里有个操作符filter,顾名思义是用来筛选数据的。而Func1这个类,用于实现具体的处理逻辑,它和Action1这个类的不同点在于有返回值。

这个例子的功能是筛选出能被2整除的数字,运行结果如下:

D/test: call:2
D/test: call:4

再看一个常用操作符,map

Observable.just(1,2,3,4,5)
        .map(new Func1<Integer, Integer>() {
            @Override
            public Integer call(Integer integer) {
                return integer*2;
            }
        })
        .subscribe(integer -> Log.d("test", "call:"+integer));

map操作符的作用是对数据进行统一的处理。在本例中是对各个数字乘以2。

运行结果如下:

D/test: call:2
D/test: call:4
D/test: call:6
D/test: call:8
D/test: call:10

还有其它各种处理数据的操作符,如得到数据的前几位,后几位,排序等。你能想到的各种常用处理,RxJava基本都有对应的操作符。

另外这个例子中使用了lambda表达式,简化了代码。

例4:线程的切换示例

使用RxJava可以很方便地进行线程切换,每一步操作都可以切换线程。如下例:

Observable.just(1, 2, 3, 4) // IO 线程,由第一个 subscribeOn() 指定
    .subscribeOn(Schedulers.io())
    .observeOn(Schedulers.newThread())
    .map(mapOperator) // 新线程,由上一行的 observeOn() 指定
    .observeOn(Schedulers.io())
    .map(mapOperator2) // IO 线程,由由上一行的 observeOn() 指定
    .observeOn(AndroidSchedulers.mainThread) 
    .subscribe(subscriber);  // Android 主线程,由由上一行的 observeOn() 指定

切换线程可以使用subscribeOn和observeOn两个操作符。这两个有什么区别呢?

subscribeOn传入的的是被观察者,即数据源产生数据时所在的线程。
observeOn传入的是处理数据所在的线程。

如果链式调用中,出现了多个subscribeOn,则数据源产生数据的线程是首个subscribeOn指定的线程。

而每调一次observeOn传入不同的线程,下一步的数据操作就会变到该线程里。

可参考扔物线的RxJava讲解

五、最后,贴上Retrofit+RxJava使用示例:

service.login(phone, password)//获取Observable对象
        .subscribeOn(Schedulers.newThread())// 定义登录操作(获取Observable对象)在新的线程进行
        .observeOn(Schedulers.io())//请求完成后在io线程中执行保存用户信息
        .doOnNext(new Action1<UserInfo>() {
            @Override
            public void call(UserInfo userInfo) {
                saveUserInfo(userInfo);//保存用户信息到数据库
            }
        })
        .observeOn(AndroidSchedulers.mainThread())//最后在主线程中执行
        .subscribe(new Subscriber<UserInfo>() {
            @Override
            public void onCompleted() {
                //操作完成
            }

            @Override
            public void onError(Throwable e) {
                //请求失败
            }

            @Override
            public void onNext(UserInfo userInfo) {
                //请求成功,显示用户信息,在主线程
				showUserInfo();
            }
        });
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章