You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Retrofit+RxJava+MVVM架构下加载多页电影数据

解决启动时加载3页电影数据的问题

首先得点明你之前方案的核心问题:你的Repository复用了同一个mMoviesResultsMutableLiveData实例,每次请求新页面时setValue都会覆盖之前的数据;再加上for循环同时发起3个请求,最终只有最后一次请求的结果会被Observer接收——毕竟LiveData的通知是覆盖式的,而且你也没做RxJava请求的结果合并。

下面给你一步步的重构方案:

第一步:重构Repository,用RxJava合并多页请求

我们可以借助RxJava的操作符,把3页请求的结果合并成一个完整的列表返回。这里用Observable.range生成1-3的页码,再通过concatMap(按顺序执行请求)或flatMap(并行执行请求)串联/并行处理每个请求,最后用reduce合并所有页的数据。

修改后的Repository代码:

public LiveData<List<MoviesResult>> getMultiPageMovies(String sort_by, int pageCount, String with_genres, String with_cast) {
    MutableLiveData<List<MoviesResult>> combinedLiveData = new MutableLiveData<>();
    MoviesService moviesService = RetrofitInstance.getMoviesService();
    String apiKey = mApplication.getResources().getString(R.string.api_key);
    boolean includeAdults = UserSettings.getInstance().includeAdults();

    // 生成1到pageCount的页码流,按顺序请求每一页
    Observable.range(1, pageCount)
            .concatMap(page -> moviesService.getMovies(apiKey, sort_by, includeAdults, true, page, with_genres, with_cast)
                    .retryWhen(throwable -> throwable.delay(5, TimeUnit.SECONDS))
                    .subscribeOn(Schedulers.io()))
            // 提取每一页的电影列表
            .map(MoviesResponse::getMoviesResults)
            // 将所有页的列表合并成一个大列表
            .reduce(new ArrayList<>(), (totalList, pageList) -> {
                totalList.addAll(pageList);
                return totalList;
            })
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(combinedList -> {
                combinedLiveData.setValue(combinedList);
            }, throwable -> {
                CustomToast customToast = new CustomToast(mApplication.getApplicationContext());
                customToast.makeCustomText(throwable.getMessage());
            });

    return combinedLiveData;
}

注:如果想并行请求可以把concatMap换成flatMap,但要注意目标API的请求频率限制,避免触发限流。

第二步:更新ViewModel层

ViewModel只需要调用新的Repository方法,直接返回合并后的LiveData即可:

public LiveData<List<MoviesResult>> getMultiPageMovies(String sort_by, int pageCount, String with_genres, String with_cast) {
    return mMoviesRepository.getMultiPageMovies(sort_by, pageCount, with_genres, with_cast);
}

第三步:修改MainActivity的调用逻辑

现在只需要订阅一次,就能拿到3页合并后的所有数据了:

mMoviesViewModel.getMultiPageMovies(getString(R.string.sort_by_popularity), 3, null, null)
        .observe(this, moviesResults -> {
            Log.d(TAG, "onChanged: 总数据量" + moviesResults.size());
            // 在这里处理合并后的完整电影列表
        });

补充:为什么之前的for循环方案失效?

  • 你的Repository每次返回同一个mMoviesResultsMutableLiveData,3个请求同时发起后,最后一次请求的setValue会覆盖前两次的结果,导致Observer只能接收到最后一页的数据。
  • 就算你每次创建新的MutableLiveData,for循环里的3个Observer会各自接收单页数据,不仅代码冗余,还需要手动合并数据,远不如RxJava操作符的方式优雅可控。

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 13:27:30