RxJava2.0学习笔记(简介,线程控制,常见操作符)

文章转载自:大神的简书

要在android中使用RxJava2,先添加Gradle配置:

    compile 'io.reactivex.rxjava2:rxjava:2.0.1'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'

RxJava简介:

先假设有两根水管:

观察者模式

产生事件的水管称作上游,即RxJava中的Observable,接受事件的水管称作下游,即RxJava中的Observer,之间的连接关系就是subscribe()。这个关系用RxJava来表示就是:

//创建一个上游 Observable:
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
    @Override
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
        emitter.onNext(1);
        emitter.onNext(2);
        emitter.onNext(3);
        emitter.onComplete();
    }
});
    //创建一个下游 Observer
    Observer<Integer> observer = new Observer<Integer>() {
        @Override
        public void onSubscribe(Disposable d) {
            Log.d(TAG, "subscribe");
        }

        @Override
        public void onNext(Integer value) {
            Log.d(TAG, "" + value);
        }

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

        @Override
        public void onComplete() {
            Log.d(TAG, "complete");
        }
    };
//建立连接
observable.subscribe(observer);     

注意:只有当上下游建立连接,也就是subscribe()方法执行的时候才开始发送事件。
此外,把这段代码连起来就是RxJava中的链式操作了。即省去了不必要的对象创建。

ObservableEmitter顾名思义为发射器,用来发出三种类型的事件,通过调用其对象的onNext(),onError(),onComplete()三个方法来发出Next,Error,Complete三个事件,需要注意以下规则:

  • 上游可以发送无限个onNext,下游也可以无限接受onNext
  • 上游发送了一个onError和OnComplete事件之后,可以继续发送剩下的事件,而下游接收到这两个事件之一,就会停止接收事件。
  • 上游可以不发送onError和OnComplete事件
  • 注意:onError和OnComplete事件的发送必须互斥并且唯一,不能发送多个,也不能同时发送两种事件

Disposable字面意思是一次性用品,可以看作是管道之间的开关,当调用其dispose()方法后,会从管道中间切开,导致下游无法接收到事件。注意:上游不会因为调用该方法停止发送事件。

来看个例子, 我们让上游依次发送1,2,3,complete,4,在下游收到第二个事件之后, 切断水管, 看看运行结果:

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                Log.d(TAG, "emit 1");
                emitter.onNext(1);
                Log.d(TAG, "emit 2");
                emitter.onNext(2);
                Log.d(TAG, "emit 3");
                emitter.onNext(3);
                Log.d(TAG, "emit complete");
                emitter.onComplete();
                Log.d(TAG, "emit 4");
                emitter.onNext(4);
            }
        }).subscribe(new Observer<Integer>() {
            private Disposable mDisposable;
            private int i;

            @Override
            public void onSubscribe(Disposable d) {
                Log.d(TAG, "subscribe");
                mDisposable = d;
            }

            @Override
            public void onNext(Integer value) {
                Log.d(TAG, "onNext: " + value);
                i++;
                if (i == 2) {
                    Log.d(TAG, "dispose");
                    mDisposable.dispose();
                    Log.d(TAG, "isDisposed : " + mDisposable.isDisposed());
                }
            }

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

            @Override
            public void onComplete() {
                Log.d(TAG, "complete");
            }
        });

运行结果为:

12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: subscribe
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: emit 1
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: onNext: 1
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: emit 2
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: onNext: 2
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: dispose
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: isDisposed : true
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: emit 3
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: emit complete
12-02 06:54:07.728 7404-7404/zlc.season.rxjava2demo D/TAG: emit 4

可以看到发送第二个事件以后水管被切断了,但是上游并没有因为发送了OnComplete事件而停止发送,并且下游的onSubscribe()方法是最先调用的。

subscribe()方法还有多个重载方法:

    public final Disposable subscribe() {}
    public final Disposable subscribe(Consumer<? super T> onNext) {}
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {} 
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete) {}
    public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError, Action onComplete, Consumer<? super Disposable> onSubscribe) {}
    public final void subscribe(Observer<? super T> observer) {}
  • 不带任何参数的表示无论上游发送什么下游不管,随意发。
  • 带有一个Consumer类型的参数的表示下游只关心上游发送的onNext事件,其他事件不管。

也就可以这样写:

        subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.d(TAG, "onNext: " + integer);
            }
        });

RxJava线程控制

通常情况下上下游是在同一线程内工作的,比如在主线程中创建一个Observable发送事件,则上游在主线程中工作,同样在主线程中创建的Observer也在主线程中接收事件。看下面的例子:

@Override                                                                                       
protected void onCreate(Bundle savedInstanceState) {                                            
    super.onCreate(savedInstanceState);                                                         
    setContentView(R.layout.activity_main);                                                     

    Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {   
        @Override                                                                               
        public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {            
            Log.d(TAG, "Observable thread is : " + Thread.currentThread().getName());           
            Log.d(TAG, "emit 1");                                                               
            emitter.onNext(1);                                                                  
        }                                                                                       
    });                                                                                         

    Consumer<Integer> consumer = new Consumer<Integer>() {                                      
        @Override                                                                               
        public void accept(Integer integer) throws Exception {                                  
            Log.d(TAG, "Observer thread is :" + Thread.currentThread().getName());              
            Log.d(TAG, "onNext: " + integer);                                                   
        }                                                                                       
    };                                                                                          

    observable.subscribe(consumer);                                                             
}

结果为:

D/TAG: Observable thread is : main
D/TAG: emit 1                     
D/TAG: Observer thread is :main   
D/TAG: onNext: 1

一般我们是在子线程中执行耗时操作,在主线程中更新UI,如下图:

这里写图片描述

黄色管子代表子线程,蓝色代表主线程,要想做到两个事件在不同的线程中执行,需要用到RxJava内置的线程调度器。

在刚才的例子中,将最后的subscribe()方法修改一下:

observable.subscribeOn(Schedulers.newThread())                                              
            .observeOn(AndroidSchedulers.mainThread())                                          
            .subscribe(consumer);

运行结果:

D/TAG: Observable thread is : RxNewThreadScheduler-2  
D/TAG: emit 1                                         
D/TAG: Observer thread is :main                       
D/TAG: onNext: 1

可以看到线程改变了,其中RxNewThread是RxJava内置的一种线程,subscribeOn()指定了上游所在的线程,observeOn()指定了下游所在的线程。

注意:对上游多次调用subscribeOn()指定线程,只有第一次指定起作用,而对于下游多次调用observeOn()指定线程,每次都会改变下游所在的线程。

在RxJava中,内置了很多线程供我们选择,并且这些线程由线程池来维护的,所以效率比较高:

  • Schedulers.io()代表IO操作的线程,通常用于网络、读写文件等IO密集的操作
  • Schedulers.computation()代表CPU计算密集的线程,例如有大量计算得操作
  • Schedulers.newThread代表常规的线程
  • AndroidSchedulers.mainThread代表Android主线程

操作符

map

map的作用是对于上游发送的每个事件都应用于一个函数,使得每个事件都按照相应的函数去变化。如图:

这里写图片描述

图中的Map函数将上游的圆形变换为了下游的正方形,代码表示为:

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).map(new Function<Integer, String>() {
            @Override
            public String apply(Integer integer) throws Exception {
                return "This is result " + integer;
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, s);
            }
        });

运行结果为:

 D/TAG: This is result 1 
 D/TAG: This is result 2 
 D/TAG: This is result 3

上游的整型数字经过map操作后在下游变成了String类型。
可以看出发来的事件都可以转换为想要的类型,Object,集合等等。

FlatMap

FlatMap作用是将上游发送事件的一个Observable变换为多个发送事件的Observables,再讲它们发送的事件合并到一个Observable中发送。如图:
这里写图片描述

分解动作:
这里写图片描述

图中的FlatMap将圆形转换为三角形和正方形,并且对于每个颜色的事件都创建了一个管道,在管道中进行变换,再将转换过的合并发送到下游。

注意:FlatMap并不能保证事件发送的顺序,如果想要保证顺序需要使用concatMap。

代码demo如下:

        Observable.create(new ObservableOnSubscribe<Integer>() {
            @Override
            public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
                emitter.onNext(1);
                emitter.onNext(2);
                emitter.onNext(3);
            }
        }).flatMap(new Function<Integer, ObservableSource<String>>() {
            @Override
            public ObservableSource<String> apply(Integer integer) throws Exception {
                final List<String> list = new ArrayList<>();
                for (int i = 0; i < 3; i++) {
                    list.add("I am value " + integer);
                }
                return Observable.fromIterable(list).delay(10,TimeUnit.MILLISECONDS);
            }
        }).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, s);
            }
        });

代码中将上游传过来的3个数字每个循环三遍添加到新创建的String管道,并且加了10ms延迟,所以输出结果可以看出不是顺序的。

将上面代码中的flatMap改为concatMap可以发现,结果是顺序的了,接收到的事件和发送的事件顺序一致。

zip

zip函数的作用是将多个Observable发送的事件组合到一起,然后将组合的事件作为整体发送到下游,它严格按照发送的顺序组合,并且发送的事件个数只与多个Observable中数据较少的那个相同。如图:
这里写图片描述

这里写图片描述

通过分解动作可以看出:

  1. 组合严格按照各个Observable发送的事件顺序,对应事件组合,不会出现交叉组合。
  2. 最终发送的组合事件个数只与Observables中数据最少的相同,因为没有事件能够取出来,就无法组合了。

demo如下:

Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {            
    @Override                                                                                         
    public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {                      
        Log.d(TAG, "emit 1");                                                                         
        emitter.onNext(1);                                                                            
        Log.d(TAG, "emit 2");                                                                         
        emitter.onNext(2);                                                                            
        Log.d(TAG, "emit 3");                                                                         
        emitter.onNext(3);                                                                            
        Log.d(TAG, "emit 4");                                                                         
        emitter.onNext(4);                                                                            
        Log.d(TAG, "emit complete1");                                                                 
        emitter.onComplete();                                                                         
    }                                                                                                 
});                                                                   

Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {              
    @Override                                                                                         
    public void subscribe(ObservableEmitter<String> emitter) throws Exception {                       
        Log.d(TAG, "emit A");                                                                         
        emitter.onNext("A");                                                                          
        Log.d(TAG, "emit B");                                                                         
        emitter.onNext("B");                                                                          
        Log.d(TAG, "emit C");                                                                         
        emitter.onNext("C");                                                                          
        Log.d(TAG, "emit complete2");                                                                 
        emitter.onComplete();                                                                         
    }                                                                                                 
});                                                                     

Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {                  
    @Override                                                                                         
    public String apply(Integer integer, String s) throws Exception {                                 
        return integer + s;                                                                           
    }                                                                                                 
}).subscribe(new Observer<String>() {                       
    @Override                                                                                         
    public void onSubscribe(Disposable d) {                                                           
        Log.d(TAG, "onSubscribe");                                                                    
    }                                                                                                 

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

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

    @Override                                                                                         
    public void onComplete() {                                                                        
        Log.d(TAG, "onComplete");                                                                     
    }                                                                                                 
});

运行结果:

D/TAG: onSubscribe     
D/TAG: emit 1          
D/TAG: emit 2          
D/TAG: emit 3          
D/TAG: emit 4          
D/TAG: emit complete1  
D/TAG: emit A          
D/TAG: onNext: 1A      
D/TAG: emit B          
D/TAG: onNext: 2B      
D/TAG: emit C          
D/TAG: onNext: 3C      
D/TAG: emit complete2  
D/TAG: onComplete

可以看出组合发送了,但是第一个Observable发送完以后才开始组合,这是因为两个Observable在同一个线程中,线程的执行肯定有先后顺序,采用上面的subscribeOn()方法将两个Observable放到不同的线程中执行,这样就可以实现一一结合了,结果如下:

D/TAG: onSubscribe    
D/TAG: emit A         
D/TAG: emit 1         
D/TAG: onNext: 1A     
D/TAG: emit B         
D/TAG: emit 2         
D/TAG: onNext: 2B     
D/TAG: emit C         
D/TAG: emit 3         
D/TAG: onNext: 3C     
D/TAG: emit complete2 
D/TAG: onComplete

可以发现Observable1中还有两个事件没有发送,因为已经没有组合对象了,发送也没有意义,前面是因为在一个线程中,所以会一次性发送完,在不同线程中,即使不发送complete,那两个事件也不会发送。

zip实践

一个界面需要展示用户的一些信息,需要从两个服务器中抓取数据,要用到zip操作符来组合抓取的信息。

首先分别定义两个请求接口:

public interface Api {
    @GET
    Observable<UserBaseInfoResponse> getUserBaseInfo(@Body UserBaseInfoRequest request);

    @GET
    Observable<UserExtraInfoResponse> getUserExtraInfo(@Body UserExtraInfoRequest request);

}

然后用zip来打包请求:

Observable<UserBaseInfoResponse> observable1 =                                            
        api.getUserBaseInfo(new UserBaseInfoRequest()).subscribeOn(Schedulers.io());      

Observable<UserExtraInfoResponse> observable2 =                                           
        api.getUserExtraInfo(new UserExtraInfoRequest()).subscribeOn(Schedulers.io());    

Observable.zip(observable1, observable2,                                                  
        new BiFunction<UserBaseInfoResponse, UserExtraInfoResponse, UserInfo>() {         
            @Override                                                                     
            public UserInfo apply(UserBaseInfoResponse baseInfo,                          
                                  UserExtraInfoResponse extraInfo) throws Exception {     
                return new UserInfo(baseInfo, extraInfo);                                 
            }                                                                             
        }).observeOn(AndroidSchedulers.mainThread())                                      
        .subscribe(new Consumer<UserInfo>() {                                             
            @Override                                                                     
            public void accept(UserInfo userInfo) throws Exception {                      
                //do something;                                                           
            }                                                                             
        });
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值