如何在Kotlin中使用RxJava实现多个有依赖关系的Retrofit请求
实现方案
你可以通过RxJava的flatMap操作符处理串行依赖请求,每一步基于上一步的返回结果发起下一个请求,同时传递中间结果,最后合并为目标CityModel。
核心逻辑说明
三个请求按串行顺序执行:
- 第一步发起
getCoordinates请求获取经纬度 - 第二步拿第一步返回的经纬度发起
getWeather请求获取天气数据,同时携带第一步的location结果 - 第三步拿城市名(或前序结果里的地址信息)发起
getPlaceId请求,最后把三个结果组装成CityModel
代码实现
class WeatherViewModel( private val weatherRepository: WeatherRepository ) : ViewModel() { // 管理RxJava订阅,避免内存泄漏 private val compositeDisposable = CompositeDisposable() // 对外暴露的UI状态 val cityResult = MutableLiveData<CityModel>() val errorMsg = MutableLiveData<String>() fun loadCityData(cityName: String) { // 第一步:获取城市经纬度 weatherRepository.getCoordinates(cityName, BuildConfig.WEATHER_API_KEY) .subscribeOn(Schedulers.io()) // 第二步:用经纬度查询天气,同时携带location结果往下传递 .flatMap { locationList -> // 处理接口返回的location列表,取第一条有效数据 val firstLocation = locationList.firstOrNull() ?: throw RuntimeException("未查询到对应城市的经纬度信息") weatherRepository.getWeather( lat = firstLocation.lat ?: throw RuntimeException("纬度信息为空"), lon = firstLocation.lon ?: throw RuntimeException("经度信息为空"), exclude = "minutely,hourly", // 可根据业务需求调整过滤参数 units = "metric", // 单位用摄氏度,可按需调整 appKey = BuildConfig.WEATHER_API_KEY ).map { weatherModel -> // 把前两步的结果配对传递 locationList to weatherModel } } // 第三步:查询placeId,合并三个结果生成CityModel .flatMap { (locationList, weatherModel) -> weatherRepository.getPlaceId( placeName = cityName, appKey = BuildConfig.PLACES_API_KEY ).map { placesModel -> CityModel( locationModel = locationList, weatherModel = weatherModel, placesModel = placesModel ) } } // 结果切换到主线程回调 .observeOn(AndroidSchedulers.mainThread()) .subscribe( { cityModel -> cityResult.value = cityModel }, { throwable -> errorMsg.value = throwable.message ?: "请求失败,请稍后重试" } ) .addTo(compositeDisposable) } override fun onCleared() { super.onCleared() // ViewModel销毁时取消所有未完成的请求 compositeDisposable.dispose() } }
注意事项
- 若你定义的
getCoordinates接口实际返回的是单个LocationModel而非列表,删除代码中firstOrNull的列表取值逻辑,直接读取locationModel的经纬度即可。 - 上述代码替换了原示例中的
!!强制非空写法,增加了空校验逻辑,避免空指针崩溃,你可以根据自己的业务模型调整校验规则。 - 不要忘记在Activity/Fragment中观察
cityResult和errorMsg来更新UI。
内容的提问来源于stack exchange,提问作者gawron103
相关产品推荐
相关产品推荐

