在返回订阅服务器之前,如何拦截可观察对象并在RxJava中修改它?

时间:2016-11-17 19:58:56

标签: java android retrofit rx-java reactive-programming

我目前正试图点击服务并返回一个对象列表,在它返回给订阅者之前,我想对列表中的每个对象进行另一个同步调用,以进行另一个服务调用来设置缺少一个领域。我成功完成了所有调用,但订阅者返回的对象有这个字段我需要设置为null。以下是我的代码示例:

示例服务:

rx.Observable<List<ExampleObject>> getExampleObject();
rx.Observable<MissingObject> getMissingObjectByFoo(@Path("foo") String foo);

示例类:

public class ExampleObject {
    String foo;
    MissingObject bar;

    public String getFoo() {
        return this.foo;
    }

    public void setFoo(String value) {
        this.foo = value;
    }

    public MissingObject getBar() {
        return this.bar;
    }

    public void setBar(MissingObject value) {
        this.bar = value;
    }
}

示例实施:

mService.getExampleObject().flatMap(new Func1<List<ExampleObject>, Observable<?>>() {
            @Override
            public Observable<List<ExampleObject>> call(List<ExampleObject> exampleObjects) {
                for (ExampleObject entry : exampleObjects) {
                    String foo = entry.getFoo();
                    mService.getMissingObjectByFoo(foo)
                            .subscribeOn(mScheduler.backgroundThread())
                            .observeOn(mScheduler.mainThread())
                            .subscribe(new Subscriber<MissingObject>() {
                        @Override
                        public void onCompleted() {

                        }

                        @Override
                        public void onError(Throwable e) {

                        }

                        @Override
                        public void onNext(MissingObject missingObject) {
                            entry.setBar(missingObject);
                        }
                    });
                }
                return Observable.just(exampleObjects);
            };

2 个答案:

答案 0 :(得分:4)

由于您更新条目的中间调用是异步的,我不认为您可以坚持使用return Post::where('user_id', Auth::user()->id)->withCount(['visitors' => function($query) { $query->where('created_at', '<=', Carbon\Carbon::now())->where('created_at', '>=', Carbon\Carbon::yesterday()); }])->get()->sum('visitors_count'); ,而应直接从List<ExampleObject>操纵ExampleObject

Observable

旁注:

如果您可以使用mService.getExampleObject() // Spread the list .flatMap(list -> Observable.from(list)) // Update your object // Here we zip the object with the missing object, // so that when the missing object is obtained, // we update the entry and emit it. .flatMap(entry -> Observable.zip( Observable.just(entry), mDocsService.getMissingObjectByFoo(entry.getFoo()), (entry, missingObject) -> { entry.setBar(missingObject); return entry; }) ) // if you really want a map after all .toList(); 中的函数取决于外部变量(条目),则可以跳过该zip。这是我试图避免的事情,但无论如何它都在这里:

map

答案 1 :(得分:3)

您正在寻找zip运算符,如下所述:Zip Operator。我想你想把你的所有电话都拉到一个拉链,所以,就像这样:

    mService.getExampleObject().flatMap(new Func1<List<ExampleObject>, Observable<ExampleObject>>() {
        @Override
        public Observable<List<ExampleObject>> call(List<ExampleObject> exampleObjects) {
            List<Observable<ExampleObject>> allTheObservables = new ArrayList<Observable<ExampleObject>>();
            for (ExampleObject entry : exampleObjects) {
                allTheObservables.add(mService.getMissingObjectByFoo(foo).map(new Func1<MissingObject, ExampleObject>() {
                    @Override
                    public ExampleObject call(MissingObject missingObject) {
                        return entry.setBar(missingObject);
                    }
                }));
            }
            return Observable.zip(allTheObservables, new FuncN<ExampleObject>() {
                @Override
                public ExampleObject call(ExampleObject... args) {
                    return Arrays.asList(args);
                }
            });
        }
    });

如果不起作用,或者存在语法问题,这是一个具体的例子,使用github api:

    service.getContributorsObservable("square", "dagger")
        .flatMap(new Func1<List<Contributor>, Observable<List<String>>>() {
            @Override
            public Observable<List<String>> call(List<Contributor> contributors) {
                List<Observable<String>> allTheObservables = new ArrayList<>(contributors.size());
                for (final Contributor contributor : contributors) {
                    allTheObservables.add(service.getContributorsObservable(contributor.login).map(new Func1<User, String>() {

                        @Override
                        public String call(User user) {
                            return contributor.login + " is " + user.name;
                        }
                    }));
                }
                return Observable.zip(allTheObservables, new FuncN<List<String>>() {
                    @Override
                    public List<String> call(Object... args) {
                        return Arrays.asList((String[]) args);
                    }
                });
            }
        });

请注意,这将进行n + 1个网络呼叫,1个用于ExampleObject的列表,然后在该列表中每ExampleObject个1个。如果可能,我强烈建议您与API的维护者交谈,以便在API端获取信息查找。只知道这将使用一些带宽!