RxAndroid学习记录

什么是RxAndroid

RxAndroid是现在比较流行的针对Android的开源RxJava库。主要用于实现异步的响应式编程。RxAndroid使用了观察者模式,通过定义被观察者Observable和使用Observable的subscribe进行订阅操作绑定观察者,对Observable的事件进行监听。当Observable发生变化或发送数据时就会通知所有订阅了该Observable的Observer。

RxAndroid的基本使用方式

Observable.just(1, 2, 3)
            .subscribe(new Observer<Integer>() {
                @Override
                public void onSubscribe(Disposable d) {
                    Log("onSubscribe");
                }
 
                @Override
                public void onNext(Integer integer) {
                    Log("onNext-" + integer);
                }
 
                @Override
                public void onError(Throwable e) {
                    Log("onError");
                }
 
                @Override
                public void onComplete() {
                    Log("onComplete");
                }
            });

这里使用Observable的just方法构建一个被观察者。just可以快速构建一个依次发送多个数据的Observable。
调用subscribe方法对创建的Observable进行订阅,Observer的onSubscribe方法在订阅时调用;每发送一个数据都会调用onNext方法,onNext的参数类型就是定义Observer的泛型,当发送出现错误时就会调用onError方法;一次事件完成后会调用onComplete方法表示一次事件的完成。

RxAndroid常用操作符

创建Observable

create

创建Observable时的方法,需要实现ObservableOnSubscribe接口,然后在ObservableOnSubsceibe接口的subscribe方法中实现订阅逻辑如下:

Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("a");
                emitter.onNext("b");
                emitter.onComplete();
            }
        });

定义一个简单的被观察者,当有观察者订阅时会调用观察者的onNext方法依次传递a和b然后结束本次事件。

just

创建一个依次发送指定参数的Observable

Observable.just(a,b).subscribe(new Consumer<String>(){
	@Override
             public void accept(String s) throws Exception {
                   Log.i(TAG, "onNext: "+s );
               }
});

这个被观察者的效果同上面的一样发送a和b后结束事件

amb和ambArray

传递多个Observable,但只有最早产生事件的Observable的事件会被消费,其他会被抛弃。
Observable.amb(Iterable<? extends ObservableSource<? extends T>> sources)需要传递一个Observable的迭代器的参数
Observable.ambArray (ObservableSource<? extends T> … sources)需要传递多个Observable对象
下面是ambArray的简单使用

Observable.ambArray(
                Observable.just(1).delay(100, TimeUnit.MILLISECONDS),
                Observable.just(2)
        ).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.i(TAG, "accept: "+integer);
            }
        });

传递两个使用just方法生成的Observable,但是第一个调用了Observable的delay方法使事件延迟发送,这里是延迟0.1秒。由于ambArray只消费第一个产生事件的Observable所以最后输出的是2。
amb和ambArray可以使用在同时向多个ip发起请求,最快响应的那个服务器将作为后续访问的节点。

concat

concat可以使传递过来的Observable进行串行执行。即上一个Observable触发onComplete或onError后,下一个Observable才开始执行。
下面是concat的所有原型方法,参数不同不过效果基本一样

static <T> Observable<T> concat(Iterable<? extends ObservableSource<? extends T>> sources);
static <T> Observable<T> concat(ObservableSource<? extends ObservableSource<? extends T>> sources, int prefetch);
static <T> Observable<T> concat(ObservableSource<? extends T> source1, ObservableSource<? extends T> source2, ObservableSource<? extends T> source3, ObservableSource<? extends T> source4)
static <T> Observable<T> concatArray(ObservableSource<? extends T>... sources);
static <T> Observable<T> concatArrayDelayError(ObservableSource<? extends T>... sources);
static <T> Observable<T> concatArrayEager(int maxConcurrency, int prefetch, ObservableSource<? extends T>... sources);
static <T> Observable<T> concatArrayEagerDelayError(int maxConcurrency, int prefetch, ObservableSource<? extends T>... sources);
static <T> Observable<T> concatDelayError(ObservableSource<? extends ObservableSource<? extends T>> sources, int prefetch, boolean tillTheEnd);
static <T> Observable<T> concatEager(Iterable<? extends ObservableSource<? extends T>> sources, int maxConcurrency, int prefetch);

以一个演示一下简单的用法:

Observable.concat(
               Observable.just("a"),
               Observable.just("b")
       ).subscribe(new Consumer<String>() {
           @Override
           public void accept(String s) throws Exception {
               Log.i(TAG,"accept:"+ s);
           }
       });

当然此处只是简单的演示参数的传递和调用,实际使用应该是几个进行复杂操作的Observable的串型调用

merge

merge是并行的触发所有的Observable,当所有子Observable都结束事件调用onComplete方法后才会触发onComplete结束事件

Observable.merge(
              Observable.just(1).delay(1000, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread()),
              Observable.just(2).delay(500,TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread()),
              Observable.just(3).delay(800,TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread())
      ).subscribe(new Consumer<Integer>() {
          @Override
          public void accept(Integer integer) throws Exception {
              Log.i(TAG, "accept: " + integer);
          }
      });

定义三个Observable并给予不同延时,由于是并行执行需要使用subscribeOn方法手动设置不同的线程进行调度,执行后可以看到依次输出 2 3 1,由于是并行执行所以延时最短的将最早输出

range

定义一个Observable指定输出初始值n和数量m输出大于等于n的m个数

Observable.range(5,10)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.i(TAG, "accept: "+ integer);
                    }
                });

Observable事件加工

filter

定义过滤器过滤不符合条件的数据。

Observable.just(2,4,5,7,8,9).filter(new Predicate<Integer>() {
          @Override
          public boolean test(Integer integer) throws Exception {
              return integer > 6;
          }
      }).subscribe(new Consumer<Integer>() {
          @Override
          public void accept(Integer integer) throws Exception {
              Log.i(TAG, "accept: "+integer);
          }
      });
map

拦截Observable发射出来的事件,并将事件的数据转化成其他数据后再发射到Observable中

Observable.just(2,4,5,7,8,9)
              .map(new Function<Integer, String>() {
                  @Override
                  public String apply(Integer integer) throws Exception {
                      return "this is "+ integer;
                  }
              }).subscribe(new Consumer<String>() {
          @Override
          public void accept(String s) throws Exception {
              Log.i(TAG, "accept: "+ s);
          }
      });

使用just定义一个发送integer类型数据的Observable,然后使用map方法将integer转化成需要输出的String类型的数据再进行发送。

flatMap

拦截Observable发射的事件,并将数据转化成Observable对象后通过这些新生成的Observable取代原有的Observable提供数据
下面是网上找的一个演示flatMap用法的例子:
假设有一群小朋友聚在一起玩耍,每个人都需要拿出自己的玩具,然后我们需要统计下这些玩具,代码如下:

class Toy {
    String name;
    Toy(String name) {
        this.name = name;
    }
}

class Kid {
    List<Toy> toys;
}

List<Kid> kids() {
    List<Kid> kids = new LinkedList<>();
    Kid kid = new Kid();
    kid.toys = new LinkedList<>();
    kid.toys.add(new Toy("熊大"));
    kid.toys.add(new Toy("熊二"));
    kids.add(kid);
    kid = new Kid();
    kid.toys = new LinkedList<>();
    kid.toys.add(new Toy("水枪"));
    kids.add(kid);
    kid = new Kid();
    kid.toys = new LinkedList<>();
    kid.toys.add(new Toy("足球"));
    kid.toys.add(new Toy("扭扭车"));
    kids.add(kid);
    return kids;
}

void test() {
   Observable.fromIterable(kids())
                .flatMap(new Function<Kid, ObservableSource<Toy>>() {
                    @Override
                    public ObservableSource<Toy> apply(Kid kid) throws Exception {
                        return Observable.fromIterable(kid.toys);
                    }
                }).subscribe(new Consumer<Toy>() {
            @Override
            public void accept(Toy toy) throws Exception {
                Log.i(TAG, "accept: "+toy.name);
            }
        });
}

上述例子就是通过flatmap将原来的泛型为kid集合的Observable转化成toy集合的Observable然后再对这新的Observable进行订阅

take

take将指定最多输出数据的数量

Observable.just(1, 2, 3, 4, 5, 6)
                .take(3)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.i(TAG, "accept: ");
                    }
                });

由于take的值是3所以将只输出1,2,3

doOnNext

在每次输出一个元素之前额外做一些事情

Observable.just(1, 2, 3, 4, 5, 6)
                .doOnNext(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.i(TAG, "accept1: " + integer);
                    }
                })
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.i(TAG, "accept2: "+integer);
                    }
                });

与这个差不多的还有doOnSubscribe,doOnComplete,doOnError分别在对应的方法前在进行一些操作

subscribeOn和observeOn

subscribeOn:设置Observable被观察者的运行线程
observeOn:设置Observer观察者运行的线程

Observable.just(1,2,3,4,5)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {

                    }
                });

这里是比较常用的两种指定线程,将Observable设置在io线程,Observer设置在ui线程,这样就能够实现Observable中进行网络请求或图片加载等耗时操作,执行完后切换到UI线程进行界面的更新

compose

将对当前的Observable进行操作,可以将原来的Observable转化成新的Observable
使用compose操作可以减少需要对Observable进行的重复操作

ObservableTransformer<Integer,Integer> transformer = new ObservableTransformer<Integer, Integer>() {
            @Override
            public ObservableSource<Integer> apply(Observable<Integer> upstream) {
                return upstream.subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread());
            }
        };
        Observable.just(1,2,3,4,5)
                .compose(transformer)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {

                    }
                });

声明一个ObservableTransformer 对Observable设置subscribeOn和observeOn,这样所有需要Observable在io线程执行,Observer在ui线程执行的Observable都可以通过compose这个ObservableTransformer进行进行操作减少部分重复的代码

实战练习

下面是学习时使用RxAndroid和retrofit进行网络请求是案例
retrofit的接口类

public interface GirlApi {
    @GET("data/福利/10/{page}")
    Observable<Result<GirlData>> fetchPrettyGirl(@Path("page") int page);
}
public class GirlRetrofit {
    private static final String GANK_URL = "http://gank.io/api/";
    private final GirlApi mGirlApi;
    public GirlRetrofit(){
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(20, TimeUnit.SECONDS);
        builder.readTimeout(15,TimeUnit.SECONDS);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(GANK_URL)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .client(builder.build())
                .build();
        mGirlApi = retrofit.create(GirlApi.class);
    }

    public GirlApi getGirlApi(){
        return mGirlApi;
    }
}

进行网络请求

 private Function<? super GirlData, ? extends ObservableSource<? extends List<Image>>> imageFetcher
            = new Function<GirlData, ObservableSource<? extends List<Image>>>() {
        @Override
        public ObservableSource<? extends List<Image>> apply(GirlData girlData) throws Exception {
            for (PrettyGirl girl : girlData.results) {
                try {
                    Bitmap bitmap = Picasso.get().load(girl.url).get();
                    Image image = new Image();
                    image.width = bitmap.getWidth();
                    image.height = bitmap.getHeight();
                    image.url = girl.url;
                    Log.w(TAG, "apply: imageUrl" + image.url);
                    mImageList.add(image);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return Observable.just(mImageList);
        }
    };
 private void fetchGirlData() {
        Observable<List<Image>> results = mGirlApi.fetchPrettyGirl(page)
                .compose(this.<Result<GirlData>>bindToLifecycle())//绑定生命周期
                .filter(new Predicate<Result<GirlData>>() {
                    @Override
                    public boolean test(Result<GirlData> girlDataResult) throws Exception {
                        return !girlDataResult.isError() && girlDataResult.response().isSuccessful();
                    }
                })//过滤掉请求失败的数据
                .map(new Function<Result<GirlData>, GirlData>() {
                    @Override
                    public GirlData apply(Result<GirlData> girlDataResult) {
                        return girlDataResult.response().body();
                    }
                })//将获取到的Result数据转化成model类
                .flatMap(imageFetcher)//对获取到的数据进行处理添加到mImageList中,再将Observable转化成Image集合类型的Observable
                .subscribeOn(Schedulers.io())//定义数据获取是在Io线程中执行
                .observeOn(AndroidSchedulers.mainThread())//由于最后涉及到ui操作需要将observer的操作定义在ui线程
                .cache();
        results.filter(new Predicate<List<Image>>() {
            @Override
            public boolean test(List<Image> o) throws Exception {
                return o.size() != 0;
            }
        })//如果集合的size为0就过滤掉不进行操作
        .compose(this.<List<Image>>bindToLifecycle())
                .doOnComplete(new Action() {
                    @Override
                    public void run() throws Exception {
                        mBinding.refreshLayout.setRefreshing(false);
                    }
                })//当数据更新结束后将refreshLayout的刷新状态改成false
        .subscribe(new Consumer<List<Image>>() {
            @Override
            public void accept(List<Image> images) throws Exception {
                mAdapter.notifyDataSetChanged();//通知recyclerView的Adapter数据集合发生改变。刷新显示
                mBinding.refreshLayout.setRefreshing(false);
            }
        }, dataError);
    }

完整的项目地址 https://github.com/zhuhaichun/MyRxAndroidDemo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值