RxJava zip操作符在Android中的实际使用场景

概述

Returns an Observable that emits the results of a specified combiner function applied to combinations of two items emitted,
in sequence, by two other Observables.

流程图:
RxJava zip操作符在Android中的实际使用场景_第1张图片

简单来说zip操作符就是合并多个数据流,
然后发送(Emit)最终合并的数据。

需求描述:

  1. 在很多app种都会有图片上传的功能,比如商品的评价,
  2. 客户端允许用户拍照上传(可能多张),
  3. 把图片上传到又拍云(现在很多中小型公司都是用又拍云作为图片服务器),
  4. 然后获取图片的url,再把图片的信息(图片url,图片大小)发送给图片。

主要逻辑:

  1. 先把所有的图片上传到又拍云(比如3张图片)
  2. 获取图片的url路径,图片大小等
  3. 最后把数据全部提交给服务器
 //需要上传的图片
        Picture[] ps = xxx;
        Observable.zip(
                Observable.from(ps),
                getUpYunAddress(ps.length),//获取上传的url
                new Func2() {
                    @Override
                    public Picture call(Picture picture, UpYunAddress upYunAddress) {
                        //如果该图片已经上传则不应该上传
                        if (TextUtils.isEmpty(picture.getSource())) {
                            try {
                                //使用又拍云提供的工具类,上传图片
                                String path = UpYunUtil.uploadImage(upYunAddress, picture.getLocalUrl());
                                //获取最终的url
                                String finalUrl = upYunAddress.getPrefix() + path;
                                picture.setSource(finalUrl);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                        return picture;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                //上传成功后获取图片大小
                .flatMap(new Func1>() {
                    @Override
                    public Observable call(Picture picture) {
                        if (TextUtils.isEmpty(picture.getHeight()) || TextUtils.isEmpty(picture.getWidth())) {
                            BitmapFactory.Options options;
                            if (!TextUtils.isEmpty(picture.getLocalUrl())) {
                                options = ImageUtil.getBitmapOptions(picture.getLocalUrl());
                                picture.setLocalUrl(null);
                            } else {
                                options = ImageUtil.getBitmapOptions(picture.getSource());
                            }
                            picture.setWidth(String.valueOf(options.outWidth));
                            picture.setHeight(String.valueOf(options.outHeight));
                        }
                        return Observable.just(picture);
                    }
                });
                //最后处理最终的数据。

扩展

假设这样一种场景,我们利用github api开发一个app,在user界面,我既要请求user基本信息,又要列举user下的event数据,为此,我准备使用Retrofit来做网络请求。

首先写好interfaces:

public interface GitHubUser {
  @GET("users/{user}")
  Observable getUser(@Path("user") String user);
}

public interface GitHubEvents {
  @GET("users/{user}/events")
  Observable listEvents(@Path("user") String user);
}

然后定义好我们的两个Observable:

Retrofit repo = new Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build();

Observable userObservable = repo
        .create(GitHubUser.class)
        .getUser(loginName)
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread());

Observable eventsObservable = repo
        .create(GitHubEvents.class)
        .listEvents(loginName)
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread());

分别是userObservable和eventsObservable,很显然的,我们将会需要两次请求。两次就两次嘛,但是这里有个问题。

虽然在后台有两次请求,但是在前台,我们希望用户打开这个页面,然后等待加载,然后显示。用户只有一次等待加载的过程。所以说,我们需要等待这两个请求都返回结果了,再开始显示数据。

怎么办?自己写判断两个都加载已完成的代码吗?逻辑好像也不是很复杂,但是代码看起来就没有那么高大上了啊。

其实既然你都用过了还有,那么直觉上你应该意识到也许RxJava可以解决这个问题。没错,就是RxJava,使用zip操作符。

zip( ):使用一个函数组合多个Observable发射的数据集合,然后再发射这个结果

“Retrofit对Observable的支持使得它可以很简单的将多个REST请求结合起来。比如我们有一个请求是获取照片的,还有一个请求是获取元数据的,我们就可以将这两个请求并发的发出,并且等待两个结果都返回之后再做处理:

Observable combined = Observable.zip(userObservable, eventsObservable, new Func2() {
  @Override
  public UserAndEvents call(JsonObject jsonObject, JsonArray jsonElements) {
    return new UserAndEvents(jsonObject, jsonElements);
  }
});

combined.subscribe(new Subscriber() {
          ...
          @Override
          public void onNext(UserAndEvents o) {
            // You can access the results of the 
            // two observabes via the POJO now
          }
        });

public class UserAndEvents {
  public UserAndEvents(JsonObject user, JsonArray events) {
    this.events = events;
    this.user = user;
  }

  public JsonArray events;
  public JsonObject user;
}

这里的UserAndEvents是我们自己定义的,目的是把原来的两个结果的信息柔和在一个对象中,毕竟新的Observable也只能返回一次。

你可能感兴趣的:(Android开发)