《NotRxJava guide for lazy folks》笔记,揭开RxJava框架原理

原文及译文

这篇文章是我目前看过的对RxJava设计原理讲解的最通俗易懂的

原文:NotRxJava guide for lazy folks
译文:NotRxJava懒人专用指南-RxJava的演进过程

需求

  1. 获取一个猫的列表
  2. 选出最可爱的那只猫
  3. 最后将这个最可爱的猫保存数据库

Cat类和API

public class Cat implements Comparable<Cat>{
    Bitmap image;
    int cuteness;
 
    @Override
    public int compareTo(Cat another) {
        return Integer.compare(cuteness, another.cuteness);
    }
}

 步骤二选出最可爱的猫是同步的过程,并不耗时,所以未定义接口

public interface Api {
    List<Cat> queryCats(String query);
    Uri store(Cat cat);
}

 同步的代码实现

public class CatsHelper {

    Api api;

    public Uri saveTheCutestCat(String query){
        try{
            // 获取一个猫的列表
            List<Cat> cats = api.queryCats(query);
            // 选出最可爱的那只猫
            Cat cutest = findCutest(cats);
            // 最后将这个最可爱的猫保存数据库
            Uri savedUri = api.store(cutest);
            return savedUri;
        } catch (Exception e) { // 错误统一处理
            e.printStackTrace()
            return someDefaultValue;
        }
    }

    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

异步代码实现

首先改变下接口的定义,处理结果由原来的直接返回变成通过回调接收

public interface Api {
    
    void queryCats(String query, CatsQueryCallback catsQueryCallback);
    void store(Cat cat, StoreCallback storeCallback);
    
    interface CatsQueryCallback {
        void onCatListReceived(List<Cat> cats);
        void onQueryFailed(Exception e);
    }

    interface StoreCallback{
        void onCatStored(Uri uri);
        void onStoreFailed(Exception e);
    }
}

 这层层的缩进,回调中的回调,就是所谓的回调地狱

public class CatsHelper {

    Api api;

    public void saveTheCutestCat(String query, CutestCatCallback cutestCatCallback) {
        // 获取一个猫的列表
        api.queryCats(query, new Api.CatsQueryCallback() {
            @Override
            public void onCatListReceived(List<Cat> cats) {
                // 选出最可爱的那只猫
                Cat cutest = findCutest(cats);
                // 最后将这个最可爱的猫保存数据库
                api.store(cutest, new Api.StoreCallback() {
                    @Override
                    public void onCatStored(Uri uri) {
                        cutestCatCallback.onCutestCatSaved(uri);
                    }

                    @Override
                    public void onStoreFailed(Exception e) {
                        cutestCatCallback.onError(e);
                    }
                });
            }

            @Override
            public void onQueryFailed(Exception e) {
                cutestCatCallback.onError(e);
            }
        });
    }

    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }

    public interface CutestCatCallback {
        void onCutestCatSaved(Uri uri);
        void onError(Exception e);
    }
}

 泛型回调

分析我们之前定义的三个回调函数CatsQueryCallback 、StoreCallback、CutestCatCallback,可以发现里面都定义了两个方法

  • 一个接收处理结果的方法,只是接收的结果类型不一样
  • 一个接收处理过程中异常的方法,接收的内容都是Exception或其子类

可以定义一个通用的泛型回调函数

public interface Callback<T> {
    void onResult(T result);
    void onError(Exception e);
}

然后再新增一个ApiWrapper类

这一步我一开始比较不能理解,为什么要在CatsQueryCallback和StoreCallback回调里再回调Callback呢?为什么不直接修改Api接口,讲queryCats()和store()方法的回调类型都设置成Callback类型呢?

这样子改当然可以,但是前提是这个Api是你自己写的,如果这个Api是在别人的jar包里提供的呢?即使是自己写的Api也不建议修改,最好的方法就是像这样再包装一层。一个好的框架就是要通用,不能说我用你这个框架还用修改自己的Api设计,这样就不合理了

包装一层将queryCats()和store()的回调都转成CallBack类型

public class ApiWrapper {
    Api api;
 
    public void queryCats(String query, Callback<List<Cat>> catsCallback){
        api.queryCats(query, new Api.CatsQueryCallback() {
            @Override
            public void onCatListReceived(List<Cat> cats) {
                catsCallback.onResult(cats);
            }
 
            @Override
            public void onQueryFailed(Exception e) {
                catsCallback.onError(e);
            }
        });
    }
 
    public void store(Cat cat, Callback<Uri> uriCallback){
        api.store(cat, new Api.StoreCallback() {
            @Override
            public void onCatStored(Uri uri) {
                uriCallback.onResult(uri);
            }
 
            @Override
            public void onStoreFailed(Exception e) {
                uriCallback.onError(e);
            }
        });
    }
}

 然后再修改CatsHelper类,这里saveTheCutestCat()的回调类型也可以改成Callback类型了。有人会问,为什么上面Api的回调采用转发而不是改成Callback类型,而这里却可以修改类型。因为上面是Api,一旦设计好不建议再修改,而CatsHelper是业务相关的类,可以修改其实现代码。

由于ApiWrapper.queryCats()、ApiWrapper.store()和CatsHelper.saveTheCutestCat()统一了回调函数的类型,所以CatsHelper.saveTheCutestCat()方法的回调直接传给了最里层的ApiWrapper.store(),这样就少了一层回调,代码也简洁了不少

public class CatsHelper{
 
    ApiWrapper apiWrapper;
 
    public void saveTheCutestCat(String query, Callback<Uri> cutestCatCallback){
        apiWrapper.queryCats(query, new Callback<List<Cat>>() {
            @Override
            public void onResult(List<Cat> cats) {
                Cat cutest = findCutest(cats);
                apiWrapper.store(cutest, cutestCatCallback);
            }
 
            @Override
            public void onError(Exception e) {
                cutestCatCallback.onError(e);
            }
        });
    }
 
    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

异步任务类AsyncJob

分析上面的queryCats()、store()和saveTheCutestCat()这些异步方法,我们可以抽象出一个异步任务类,暂且就叫做AsyncJob。

定义如下,接口里有个start方法,在里面可以具体实现任务内容,该方法接收Callback回调

public abstract class AsyncJob<T> {
    public abstract void start(Callback<T> callback);
}

然后修改ApiWrapper包装类里的queryCats()和store()方法,各返回一个具体的AsyncJob实现。

需要注意的是这两个方法的逻辑变了,之前的实现是执行异步任务,现在是返回异步任务AsyncJob,但是并未执行异步任务。异步任务被放在了start方法里(可以发现start方法参数和内容和原来的实现一模一样),需要调用返回的AsyncJob的start方法才会开始执行异步任务

public class ApiWrapper {
    Api api;
 
    public AsyncJob<List<Cat>> queryCats(String query) {
        return new AsyncJob<List<Cat>>() {
            @Override
            public void start(Callback<List<Cat>> catsCallback) {
                api.queryCats(query, new Api.CatsQueryCallback() {
                    @Override
                    public void onCatListReceived(List<Cat> cats) {
                        catsCallback.onResult(cats);
                    }
 
                    @Override
                    public void onQueryFailed(Exception e) {
                        catsCallback.onError(e);
                    }
                });
            }
        };
    }
 
    public AsyncJob<Uri> store(Cat cat) {
        return new AsyncJob<Uri>() {
            @Override
            public void start(Callback<Uri> uriCallback) {
                api.store(cat, new Api.StoreCallback() {
                    @Override
                    public void onCatStored(Uri uri) {
                        uriCallback.onResult(uri);
                    }
 
                    @Override
                    public void onStoreFailed(Exception e) {
                        uriCallback.onError(e);
                    }
                });
            }
        };
    }
}

然后再修改CatsHelper.saveTheCutestCat()方法,也是改成返回一个AsyncJob。在start实现里是执行queryCats返回的AsyncJob异步任务,成功后再调用store返回的AsyncJob。正如我上面所说的,要调用AsyncJob.start方法才开启异步任务。

public class CatsHelper {
 
    ApiWrapper apiWrapper;
 
    public AsyncJob<Uri> saveTheCutestCat(String query) {
        return new AsyncJob<Uri>() {
            @Override
            public void start(Callback<Uri> cutestCatCallback) {
                apiWrapper.queryCats(query)
                        .start(new Callback<List<Cat>>() {
                            @Override
                            public void onResult(List<Cat> cats) {
                                Cat cutest = findCutest(cats);
                                apiWrapper.store(cutest)
                                        .start(new Callback<Uri>() {
                                            @Override
                                            public void onResult(Uri result) {
                                                cutestCatCallback.onResult(result);
                                            }
 
                                            @Override
                                            public void onError(Exception e) {
                                                cutestCatCallback.onError(e);
                                            }
                                        });
                            }
 
                            @Override
                            public void onError(Exception e) {
                                cutestCatCallback.onError(e);
                            }
                        });
            }
        };
    }
 
    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

我相信很多人看了上面修改后的CatsHelper类又要开始吐槽了,怎么又改复杂了,看看这迷之缩进。

引进这AsyncJob到底有什么好处呢?别急,好戏才刚要开始。

Map实现

我们修改下CatsHelper,降获取最可爱的猫这个过程也改成一个AsyncJob任务cutestCatAsyncJob,其start实现是先执行catsListAsyncJob任务,然后在成功的回调里再执行findCutest()方法。

然后storedUriAsyncJob的start方法里在来执行这个cutestCatAsyncJob

修改完虽然没有简单多少,但是逻辑清晰许多,仔细看catsListAsyncJob、cutestCatAsyncJob、storedUriAsyncJob这三个任务一个个列下来,是不是有点最开始的同步代码的实现的那种感觉,逻辑也比较清晰。

cutestCatAsyncJob任务里包含catsListAsyncJob

而storedUriAsyncJob包含cutestCatAsyncJob(即包含catsListAsyncJob和cutestCatAsyncJob这两个任务)

public class CatsHelper {
 
    ApiWrapper apiWrapper;
 
    public AsyncJob<Uri> saveTheCutestCat(String query) {
        AsyncJob<List<Cat>> catsListAsyncJob = apiWrapper.queryCats(query);
        AsyncJob<Cat> cutestCatAsyncJob = new AsyncJob<Cat>() {
            @Override
            public void start(Callback<Cat> callback) {
                catsListAsyncJob.start(new Callback<List<Cat>>() {
                    @Override
                    public void onResult(List<Cat> result) {
                        Cat cutest = findCutest(cats);
                        callback.onResult(cutest);
                    }
 
                    @Override
                    public void onError(Exception e) {
                        callback.onError(e);
                    }
                });
            }
        };
 
        AsyncJob<Uri> storedUriAsyncJob = new AsyncJob<Uri>() {
            @Override
            public void start(Callback<Uri> cutestCatCallback) {
                cutestCatAsyncJob.start(new Callback<Cat>() {
                    @Override
                    public void onResult(Cat cutest) {
                        apiWrapper.store(cutest)
                                .start(new Callback<Uri>() {
                                    @Override
                                    public void onResult(Uri result) {
                                        cutestCatCallback.onResult(result);
                                    }
 
                                    @Override
                                    public void onError(Exception e) {
                                        cutestCatCallback.onError(e);
                                    }
                                });
                    }
 
                    @Override
                    public void onError(Exception e) {
                        cutestCatCallback.onError(e);
                    }
                });
            }
        };
        return storedUriAsyncJob;
    }
 
    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

这里先重点看下cutestCatAsyncJob任务的实现

AsyncJob<Cat> cutestCatAsyncJob = new AsyncJob<Cat>() {
    @Override
    public void start(Callback<Cat> callback) {
        catsListAsyncJob.start(new Callback<List<Cat>>() {
            @Override
            public void onResult(List<Cat> result) {
                Cat cutest = findCutest(cats);
                callback.onResult(cutest);
            }

            @Override
            public void onError(Exception e) {
                callback.onError(e);
            }
        });
    }
};

我们先把他放进一个叫做createCutestCatAsyncJob()的方法里再来做说明,看下这个方法能不能抽象出一个通用的方法。

createCutestCatAsyncJob方法是把一个AsyncJob(获取猫列表)转化成另一个AsyncJob(获取最可爱的猫)。

其中和转化业务有关的关键代码是Cat cutest = findCutest(cats)这句话,把List<Cat>转成Cat,我们可以把这句话用一个转化接口抽出来,其余的代码成为通用的模板

private void createCutestCatAsyncJob(AsyncJob<List<Cat>> catsListAsyncJob) {
    AsyncJob<Cat> cutestCatAsyncJob = new AsyncJob<Cat>() {
        @Override
        public void start(Callback<Cat> callback) {
            catsListAsyncJob.start(new Callback<List<Cat>>() {
                @Override
                public void onResult(List<Cat> result) {
                    Cat cutest = findCutest(cats);
                    callback.onResult(cutest);
                }

                @Override
                public void onError(Exception e) {
                    callback.onError(e);
                }
            });
        }
    };
    return cutestCatAsyncJob;
}

 Func这个接口定义了一个方法call,作用是吧参数T类型转化成返回值R类型,具体转化由用户自己实现

public interface Func<T, R> {
    R call(T t);
}

利用Func接口,我们定义一个通用的转化方法,就叫做Map吧,和RxJava里的一样,定义如下

public <R> AsyncJob<R> map(AsyncJob<T> source, Func<T, R> func){
    return new AsyncJob<R>() {
        @Override
        public void start(Callback<R> callback) {
            source.start(new Callback<T>() {
                @Override
                public void onResult(T result) {
                    R mapped = func.call(result);
                    callback.onResult(mapped);
                }

                @Override
                public void onError(Exception e) {
                    callback.onError(e);
                }
            });
        }
    };
}

再把这个方法放在AsyncJob里面,这样AsyncJob对象就可以直接调用map方法,映射成另一个AsyncJob了,修改后的AsyncJob如下所示

public abstract class AsyncJob<T> {
    public abstract void start(Callback<T> callback);
 
    public <R> AsyncJob<R> map(Func<T, R> func){
        final AsyncJob<T> source = this;
        return new AsyncJob<R>() {
            @Override
            public void start(Callback<R> callback) {
                source.start(new Callback<T>() {
                    @Override
                    public void onResult(T result) {
                        R mapped = func.call(result);
                        callback.onResult(mapped);
                    }
 
                    @Override
                    public void onError(Exception e) {
                        callback.onError(e);
                    }
                });
            }
        };
    }
}

利用map方法,CatsHelper修改如下

public class CatsHelper {
 
    ApiWrapper apiWrapper;
 
    public AsyncJob<Uri> saveTheCutestCat(String query) {
        AsyncJob<List<Cat>> catsListAsyncJob = apiWrapper.queryCats(query);
        AsyncJob<Cat> cutestCatAsyncJob = catsListAsyncJob.map(new Func<List<Cat>, Cat>() {
            @Override
            public Cat call(List<Cat> cats) {
                return findCutest(cats);
            }
        });
 
        AsyncJob<Uri> storedUriAsyncJob = new AsyncJob<Uri>() {
            @Override
            public void start(Callback<Uri> cutestCatCallback) {
                cutestCatAsyncJob.start(new Callback<Cat>() {
                    @Override
                    public void onResult(Cat cutest) {
                        apiWrapper.store(cutest)
                                .start(new Callback<Uri>() {
                                    @Override
                                    public void onResult(Uri result) {
                                        cutestCatCallback.onResult(result);
                                    }
 
                                    @Override
                                    public void onError(Exception e) {
                                        cutestCatCallback.onError(e);
                                    }
                                });
                    }
 
                    @Override
                    public void onError(Exception e) {
                        cutestCatCallback.onError(e);
                    }
                });
            }
        };
        return storedUriAsyncJob;
    }
 
    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

FlatMap实现

既然map这么好用我们试着把下面这段的代码也有话一下吧,这一坨代码看着实在是不舒服

试着将cutestCatAsyncJob转成storedUriAsyncJob

AsyncJob<Uri> storedUriAsyncJob = new AsyncJob<Uri>() {
    @Override
    public void start(Callback<Uri> cutestCatCallback) {
        cutestCatAsyncJob.start(new Callback<Cat>() {
            @Override
            public void onResult(Cat cutest) {
                apiWrapper.store(cutest)
                        .start(new Callback<Uri>() {
                            @Override
                            public void onResult(Uri result) {
                                cutestCatCallback.onResult(result);
                            }

                            @Override
                            public void onError(Exception e) {
                                cutestCatCallback.onError(e);
                            }
                        });
            }

            @Override
            public void onError(Exception e) {
                cutestCatCallback.onError(e);
            }
        });
    }
};

修改后的CatsHelper代码如下

public class CatsHelper {
 
    ApiWrapper apiWrapper;
 
    public AsyncJob<Uri> saveTheCutestCat(String query) {
        AsyncJob<List<Cat>> catsListAsyncJob = apiWrapper.queryCats(query);
        AsyncJob<Cat> cutestCatAsyncJob = catsListAsyncJob.map(new Func<List<Cat>, Cat>() {
            @Override
            public Cat call(List<Cat> cats) {
                return findCutest(cats);
            }
        });
 
        AsyncJob<AsyncJob<Uri>> storedUriAsyncJob = cutestCatAsyncJob.map(new Func<Cat, AsyncJob<Uri>>() {
            @Override
            public AsyncJob<Uri> call(Cat cat) {
                return apiWrapper.store(cat);
            }
        });
        return storedUriAsyncJob;
        //^^^^^^^^^^^^^^^^^^^^^^^ will not compile
        //      Incompatible types:
        //      Required: AsyncJob<Uri>
        //      Found: AsyncJob<AsyncJob<Uri>>
    }
 
    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

 可是报错了,没事,返回值比匹配那就该一下,改成AsyncJob<Uri>不久得了,如下所示

public class CatsHelper {
 
    ApiWrapper apiWrapper;
 
    public AsyncJob<Uri> saveTheCutestCat(String query) {
        AsyncJob<List<Cat>> catsListAsyncJob = apiWrapper.queryCats(query);
        AsyncJob<Cat> cutestCatAsyncJob = catsListAsyncJob.map(new Func<List<Cat>, Cat>() {
            @Override
            public Cat call(List<Cat> cats) {
                return findCutest(cats);
            }
        });
 
        AsyncJob<AsyncJob<Uri>> storedUriAsyncJob = cutestCatAsyncJob.map(new Func<Cat, AsyncJob<Uri>>() {
            @Override
            public AsyncJob<Uri> call(Cat cat) {
                return apiWrapper.store(cat);
            }
        });
        return storedUriAsyncJob;
        //^^^^^^^^^^^^^^^^^^^^^^^ will not compile
        //      Incompatible types:
        //      Required: AsyncJob<Uri>
        //      Found: AsyncJob<AsyncJob<Uri>>
    }
 
    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

还是报错,saveTheCutestCat要的返回值是AsyncJob<Uri>,而不是AsyncJob<AsyncJob<Uri>>

AsyncJob<AsyncJob<Uri>>变成两个异步任务嵌套了

这是因为findCutest(cats)是同步代码,方法执行完可以直接得到处理完的结果

而apiWrapper.store()是异步任务,要等待执行完才能够得到处理的结果

既然这样的话何不apiWrapper.store().start()开启异步任务,等任务执行完再返回结果,这样的话map就不适用了,我们再定义一个叫做flatMap的方法,如下所示

可以看到flatMap的参数Func<T, AsyncJob<R>>,第二个泛型是个AsyncJob异步任务,所以Func.call()方法执行完返回的是一个AsyncJob异步任务,接下来再直接运行该异步,等该任务运行完再回调

public abstract class AsyncJob<T> {
    public abstract void start(Callback<T> callback);
 
    public <R> AsyncJob<R> map(Func<T, R> func){
        final AsyncJob<T> source = this;
        return new AsyncJob<R>() {
            @Override
            public void start(Callback<R> callback) {
                source.start(new Callback<T>() {
                    @Override
                    public void onResult(T result) {
                        R mapped = func.call(result);
                        callback.onResult(mapped);
                    }
 
                    @Override
                    public void onError(Exception e) {
                        callback.onError(e);
                    }
                });
            }
        };
    }
 
    public <R> AsyncJob<R> flatMap(Func<T, AsyncJob<R>> func){
        final AsyncJob<T> source = this;
        return new AsyncJob<R>() {
            @Override
            public void start(Callback<R> callback) {
                source.start(new Callback<T>() {
                    @Override
                    public void onResult(T result) {
                        AsyncJob<R> mapped = func.call(result);
                        mapped.start(new Callback<R>() {
                            @Override
                            public void onResult(R result) {
                                callback.onResult(result);
                            }
 
                            @Override
                            public void onError(Exception e) {
                                callback.onError(e);
                            }
                        });
                    }
 
                    @Override
                    public void onError(Exception e) {
                        callback.onError(e);
                    }
                });
            }
        };
    }
}

最后利用flatMap,CatsHelper修改后的代码如下,是不是一下子清爽了许多,是不是越来越像一开始的同步代码实现的三个步骤,可怕的回调地狱嵌套也减少到只有一层回调

public class CatsHelper {
 
    ApiWrapper apiWrapper;
 
    public AsyncJob<Uri> saveTheCutestCat(String query) {
        // 获取一个猫的列表
        AsyncJob<List<Cat>> catsListAsyncJob = apiWrapper.queryCats(query);
        // 选出最可爱的那只猫
        AsyncJob<Cat> cutestCatAsyncJob = catsListAsyncJob.map(new Func<List<Cat>, Cat>() {
            @Override
            public Cat call(List<Cat> cats) {
                return findCutest(cats);
            }
        });
        // 最后将这个最可爱的猫保存数据库
        AsyncJob<Uri> storedUriAsyncJob = cutestCatAsyncJob.flatMap(new Func<Cat, AsyncJob<Uri>>() {
            @Override
            public AsyncJob<Uri> call(Cat cat) {
                return apiWrapper.store(cat);
            }
        });
        return storedUriAsyncJob;
    }
 
    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

还可以改成如下的链式调用,是不是感觉很熟悉,和RxJava的使用一模一样

public class CatsHelper {

    ApiWrapper apiWrapper;

    public AsyncJob<Uri> saveTheCutestCat(String query) {
        AsyncJob<Uri> storedUriAsyncJob = apiWrapper.queryCats(query)
                .map(new Func<List<Cat>, Cat>() {
                    @Override
                    public Cat call(List<Cat> cats) {
                        return findCutest(cats);
                    }
                })
                .flatMap(new Func<Cat, AsyncJob<Uri>>() {
                    @Override
                    public AsyncJob<Uri> call(Cat cat) {
                        return apiWrapper.store(cat);
                    }
                });
        return storedUriAsyncJob;
    }

    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

当然我们这个例子只是为了让大家好理解RxJava的实现原理,以下是我们实现的类和RxJava中对应的类

  • AsyncJob对应Observable
  • Callback对应Observer
  • AsyncJob.start()方法对应Observable.subscribe方法
  • 出了map和flatMap外,RxJava中还定义了很多功能丰富的操作符

下面是用RxJava实现的代码

public class ApiWrapper {
    Api api;
 
    public Observable<List<Cat>> queryCats(final String query) {
        return Observable.create(new Observable.OnSubscribe<List<Cat>>() {
            @Override
            public void call(final Subscriber<? super List<Cat>> subscriber) {
                api.queryCats(query, new Api.CatsQueryCallback() {
                    @Override
                    public void onCatListReceived(List<Cat> cats) {
                        subscriber.onNext(cats);
                    }
 
                    @Override
                    public void onQueryFailed(Exception e) {
                        subscriber.onError(e);
                    }
                });
            }
        });
    }
 
    public Observable<Uri> store(final Cat cat) {
        return Observable.create(new Observable.OnSubscribe<Uri>() {
            @Override
            public void call(final Subscriber<? super Uri> subscriber) {
                api.store(cat, new Api.StoreCallback() {
                    @Override
                    public void onCatStored(Uri uri) {
                        subscriber.onNext(uri);
                    }
 
                    @Override
                    public void onStoreFailed(Exception e) {
                        subscriber.onError(e);
                    }
                });
            }
        });
    }
}
 
public class CatsHelper {
 
    ApiWrapper apiWrapper;
 
    public Observable<Uri> saveTheCutestCat(String query) {
        Observable<List<Cat>> catsListObservable = apiWrapper.queryCats(query);
        Observable<Cat> cutestCatObservable = catsListObservable.map(new Func1<List<Cat>, Cat>() {
            @Override
            public Cat call(List<Cat> cats) {
                return CatsHelper.this.findCutest(cats);
            }
        });
        Observable<Uri> storedUriObservable = cutestCatObservable.flatMap(new Func1<Cat, Observable<? extends Uri>>() {
            @Override
            public Observable<? extends Uri> call(Cat cat) {
                return apiWrapper.store(cat);
            }
        });
        return storedUriObservable;
    }
 
    private Cat findCutest(List<Cat> cats) {
        return Collections.max(cats);
    }
}

 

 

 

 

posted @ 2020-02-15 21:03  野猿新一  阅读(25)  评论(0编辑  收藏  举报