【问题标题】:RxJava flatMapIterable with concatMapRxJava flatMapIterable 与 concatMap
【发布时间】:2017-02-16 23:56:43
【问题描述】:

我有 2 个改装电话需要进行 A 和 B:

(A):返回一个数组列表

(B):获取 (A) 的结果,它是一个 ArrayList。 (B) 遍历 ArrayList 并使用 each 进行改造调用,并将生成的数据组合成最终的 ArrayList,该 ArrayList 将发送给我的订阅者 onNext()

我能够让它与 flatmap 一起使用,但解决方案不是很优雅。据我了解,更好的解决方案是将 flatMapIterable 与 concatMap 一起使用,但我似乎无法采用我对 flatMapIterable 和 concatMap 所做的工作。

ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
                .flatMap(new Func1<UserSelfFollows, Observable<? extends ArrayList<Media.MediaData>>>() {
                    @Override
                    public Observable<? extends ArrayList<Media.MediaData>> call(UserSelfFollows userSelfFollows) {

                        //make second requests based on response from First request to get all Users
                        ArrayList<Media.MediaData> arAllMedia = new ArrayList<>();
                        for(UserSelfFollows.UserDataFollows user : userSelfFollows.userdata){

                            Response <ResponseBody> response ;
                            Call <ResponseBody> call;
                            try {
                                call = ServiceFactory.createRetrofitService().getMediaOfUser(user.id,sessionMgr.getAuthToken());
                                response =  call.execute();
                            }catch(IOException ex){
                                return Observable.error(ex);
                            }

                            if (response.isSuccessful()) {

                                try {
                                    String str = responseHelper.streamToString( response.body().byteStream());
                                    Gson gson = new GsonBuilder().create();
                                    Media media = gson.fromJson(str, Media.class);

                                    arAllMedia.addAll(media.mediaData);

                                } catch (IOException e) {
                                    return Observable.error(e);
                                }
                            } else {
                                return Observable.error( new Exception(  responseHelper.getErrorString( response.errorBody().byteStream())) );
                            }
                        }
                        return Observable.just(arAllMedia);

                    }
                })
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<ArrayList<Media.MediaData>>() {
                    @Override
                    public final void onCompleted() {

                    }

                    @Override
                    public final void onError(Throwable e) {

                    }

                    @Override
                    public final void onNext(ArrayList<Media.MediaData> arMedia) {

                    }
                })

这是我目前所拥有的,但它不会编译:

ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
            .flatMapIterable(new Func1<UserSelfFollows, Iterable<?>>() {
                @Override
                public Iterable<?> call(UserSelfFollows userSelfFollows) {
                    return userSelfFollows.userdata;
                }
            })
            .<Media.MediaData>flatMap(new Func1<UserSelfFollows.UserDataFollows, Observable<Media.MediaData>>() {
                @Override
                public Observable<Media.MediaData> call(UserSelfFollows.UserDataFollows user) {
                    return ServiceFactory.createRetrofitService().getMediaOfUser(user.id, sessionMgr.getAuthToken());
                }
            })
            .toList();

错误是:

【问题讨论】:

    标签: android rx-java concatmap


    【解决方案1】:

    如果我正确理解您的场景,您可以使用flatMapIterable,然后使用flatMap 运算符,最后使用toList 收集所有改造调用结果。
    在第一个 flatMapIterable 中,您将从第一次调用 (getUserFollowing()) 获得的 UserDataFollows 列表扁平化为从该列表发出多个项目的 Obsevrable,然后 flatMap 创建一个 Observable 进行改造调用每个UserSelfFollows.UserDataFollows 数据对象,(它将并行发生,这似乎更适合这里,但如果您对顺序执行感兴趣,也可以使用concatMap),然后将所有最终数据收集在一起,作为@ 列表987654331@对象,可以使用toList

    ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
                .flatMapIterable(new Func1<UserSelfFollows, Iterable<?>>() {
                    @Override
                    public Iterable<?> call(UserSelfFollows userSelfFollows) {
                        return userSelfFollows.userdata;
                    }
                })
                .flatMap(new Func1<UserSelfFollows, Observable<Media>>() {
                    @Override
                    public Observable<Media> call(UserSelfFollows user) {
                        return ServiceFactory.createRetrofitService().getMediaOfUser(user.id, sessionMgr.getAuthToken());
                    }
                })
                .toList()
                .subscribe(new Action1<List<Media>>() {
                    @Override
                    public void call(List<Media> rs) {
                        //do something with the list of media data
                    }
                });
    

    【讨论】:

    • 此行不编译:return ServiceFactory.createRetrofitService().getMediaOfUser(user.id, sessionMgr.getAuthToken()); 'user' 没有属性 'id' .....我已经用你的代码更新了我的问题和抛出的错误。
    • 您的代码基本上抛出了与我的代码相同的错误
    • 嗯,从你提供的 sn-p 中解决这样的编译问题是相当困难的,我不确定你的方法返回的确切类型是什么,我根据你的做了模拟代码流,以及每个方法似乎返回的类型,无论如何,如果你有困难,你可以让自动完成功能使用 flatMap 完成它的工作,它会建议你预期的正确类型。
    • 根据您的代码,我已更新答案以反映正确的 Media 对象而不是 MediaData
    • 它没有编译的主要原因是缺少返回类型:Iterable> 但我确实赞成你的答案,因为它确实有帮助。
    【解决方案2】:

    我从未同时使用过flatMapIterableconcatMap,但作为替代解决方案,您可以使用flatMapcompose 运算符:

    ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
       .flatMap(list -> Observable.from(list))
       .compose(getComposer())
       .subscribe(mediaData -> mMediaDataList.add(mediaData), throwable -> {}, () -> { // on complete do something with mMediaList});
    

    getComposer() 返回一个 Transformer UserSelfFollows -> Media.MediaData

    protected Observable.Transformer<UserSelfFollows, Media.MediaData> getComposer() {
        return  ;
    }
    

    【讨论】:

    • 没有lamba也是一样的。在运算符内部使用 new。 AndroidStudio 会建议实施什么
    【解决方案3】:

    Yosriz 的回答让我朝着正确的方向前进。因此,为了避免其他人为此拉扯头发,这里是完整的代码解决方案:

    ServiceFactory.createRetrofitService().getUserFollowing(sessionMgr.getAuthToken())
                    .flatMapIterable(new Func1<UserSelfFollows, Iterable<UserSelfFollows.UserDataFollows>>() {
                        @Override
                        public Iterable< UserSelfFollows.UserDataFollows > call(UserSelfFollows userSelfFollows) {
                            return userSelfFollows.userdata;
                        }
                    })
                    .flatMap(new Func1<UserSelfFollows.UserDataFollows, Observable<Media>>() {
                        @Override
                        public Observable<Media> call(UserSelfFollows.UserDataFollows user) {
                            return ServiceFactory.createRetrofitService().getMediaOfUser(user.id, sessionMgr.getAuthToken());
                        }
                    })
                    .toList()
                    .subscribeOn(Schedulers.newThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Subscriber<List<Media>>() {
                        @Override
                        public final void onCompleted() {
    
                        }
    
                        @Override
                        public final void onError(Throwable e) {
    
                            userMessageHandler.showDialog(mParentActivity, mParentActivity.getString(R.string.error_retrieving_data_title),
                                    mParentActivity.getString(R.string.error_self_following_media) + e.getMessage(), 0);
                        }
    
                        @Override
                        public final void onNext(List<Media> arMedia) {
    
                            if (arMedia.size() == 0)
                                userMessageHandler.showToast(mParentActivity, mParentActivity.getString(R.string.warn_no_following));
                            else {
    
                                ArrayList<Media.MediaData> allMedia = new ArrayList<>();
                                for(Media media : arMedia){
                                    allMedia.addAll(media.mediaData);
                                }
                                mBinding.gridview.setAdapter(new MediaGridViewAdapter(mParentActivity,FollowingViewModel.this, allMedia));
                            }
                        }
                    });
    

    【讨论】:

    • 太棒了!如果有帮助,请接受我的回答:)
    猜你喜欢
    • 2017-08-04
    • 1970-01-01
    • 2017-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多