Android MVVM架构:如何让ViewModel依次发起API请求
解决MVVM模式下API请求顺序执行的问题
嘿,我来帮你搞定这个MVVM下顺序执行API请求的问题~你现在遇到的核心问题是三个ViewModel的API调用同时触发,导致后续请求拿不到前一个请求的依赖值,下面给你几个实用的解决方案,适配不同的场景:
方案一:回调嵌套(快速实现,适合Java项目)
这是最直接的方式,在第一个API请求的onChanged回调里,确认拿到有效响应后再触发第二个请求,以此类推。这样就能严格保证请求的顺序,而且不需要改动太多现有代码:
void getInspirationDetails() { inspirationDetailsModel.getInspirationDetails(userid, deviceId, inspirationId, Constants.PLATFORM) .observe(InspirationUploadDetailsActivity.this, new Observer<MainInspirationDetailsResponse>() { @Override public void onChanged(MainInspirationDetailsResponse mainInspirationDetailsResponse) { // 先校验响应的有效性,比如非空、请求成功等 if (mainInspirationDetailsResponse != null && mainInspirationDetailsResponse.isSuccess()) { // 从第一个响应中提取第二个API需要的依赖值 String targetInspirationId = mainInspirationDetailsResponse.getInspirationId(); // 触发第二个API请求 getProducts(targetInspirationId); } } }); } // 修改getProducts方法,接收依赖参数 void getProducts(String dependentInspirationId) { productsDetailsModel.getProductsItems(dependentInspirationId, "", "N", "ALL", "", "") .observe(this, new Observer<MainProductsResponse>() { @Override public void onChanged(MainProductsResponse mainProductsResponse) { // 处理第二个API的响应 // 如果还有第三个请求,就在这里继续触发第三个ViewModel的调用 } }); }
优点:实现简单,上手快,适合快速解决问题;缺点:如果请求链较长(比如三个以上),会出现回调嵌套的情况,代码可读性会下降。
方案二:用LiveData Transformations实现链式调用(更符合MVVM架构)
把请求的顺序逻辑从Activity转移到ViewModel中,利用Transformations.switchMap实现LiveData的链式依赖,让Activity只负责UI观察,职责更清晰:
第一步:在ViewModel中封装链式逻辑
public class YourCoordinatorViewModel extends ViewModel { private MutableLiveData<Object> triggerFirstRequest = new MutableLiveData<>(); private LiveData<MainInspirationDetailsResponse> firstResponseLiveData; private LiveData<MainProductsResponse> secondResponseLiveData; // 如果有第三个请求,继续定义第三个LiveData public YourCoordinatorViewModel() { // 第一个请求:当triggerFirstRequest被触发时,发起第一个API调用 firstResponseLiveData = Transformations.switchMap(triggerFirstRequest, input -> { return inspirationDetailsModel.getInspirationDetails(userid, deviceId, inspirationId, Constants.PLATFORM); }); // 第二个请求:依赖第一个请求的响应结果 secondResponseLiveData = Transformations.switchMap(firstResponseLiveData, firstResp -> { if (firstResp != null && firstResp.isSuccess()) { String dependentId = firstResp.getInspirationId(); return productsDetailsModel.getProductsItems(dependentId, "", "N", "ALL", "", ""); } else { // 第一个请求失败时,返回空的LiveData或者错误状态 return MutableLiveData.empty(); } }); // 第三个请求同理,依赖第二个请求的响应 // thirdResponseLiveData = Transformations.switchMap(secondResponseLiveData, ...) } // 对外暴露触发第一个请求的方法 public void startSequentialRequests() { triggerFirstRequest.setValue(new Object()); // 传任意值触发即可 } // 对外提供响应LiveData,供Activity观察 public LiveData<MainInspirationDetailsResponse> getFirstResponse() { return firstResponseLiveData; } public LiveData<MainProductsResponse> getSecondResponse() { return secondResponseLiveData; } }
第二步:在Activity中观察LiveData并触发请求
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 初始化ViewModel YourCoordinatorViewModel viewModel = new ViewModelProvider(this).get(YourCoordinatorViewModel.class); // 观察第一个请求的响应 viewModel.getFirstResponse().observe(this, firstResp -> { // 更新UI或处理第一个响应的数据 }); // 观察第二个请求的响应 viewModel.getSecondResponse().observe(this, secondResp -> { // 更新UI或处理第二个响应的数据 }); // 触发顺序请求 viewModel.startSequentialRequests(); }
优点:完全符合MVVM的职责分离,逻辑集中在ViewModel,Activity代码更简洁;扩展性强,新增请求只需要在ViewModel中添加新的switchMap即可;缺点:需要对LiveData的Transformations有一定了解,适合有一定MVVM基础的开发者。
方案三:协程顺序执行(Kotlin项目首选)
如果你的项目用的是Kotlin,用协程可以写出更简洁、无回调的顺序请求代码,利用viewModelScope保证请求在ViewModel生命周期内执行:
class YourViewModel : ViewModel() { private val _firstResponse = MutableLiveData<MainInspirationDetailsResponse?>() val firstResponse: LiveData<MainInspirationDetailsResponse?> = _firstResponse private val _secondResponse = MutableLiveData<MainProductsResponse?>() val secondResponse: LiveData<MainProductsResponse?> = _secondResponse fun fetchSequentially() { viewModelScope.launch { try { // 第一个请求,await()将LiveData转为挂起函数 val firstResp = inspirationDetailsModel.getInspirationDetails(userid, deviceId, inspirationId, Constants.PLATFORM).await() _firstResponse.value = firstResp if (firstResp != null && firstResp.isSuccess()) { // 第二个请求,依赖第一个的结果 val secondResp = productsDetailsModel.getProductsItems(firstResp.inspirationId, "", "N", "ALL", "", "").await() _secondResponse.value = secondResp } } catch (e: Exception) { // 统一处理请求异常,比如弹出错误提示 e.printStackTrace() } } } }
然后在Activity中调用:
viewModel.fetchSequentially() viewModel.firstResponse.observe(this) { firstResp -> // 处理第一个响应 } viewModel.secondResponse.observe(this) { secondResp -> // 处理第二个响应 }
优点:代码线性、无回调,可读性极强;异常处理更统一;缺点:仅适用于Kotlin项目,需要引入协程相关依赖。
内容的提问来源于stack exchange,提问作者user6043117
相关产品推荐
相关产品推荐

