Android MVVM下API重复调用与配置变更问题求解
问题分析
横竖屏切换时重复发起API请求的核心原因:
- Activity配置变更会触发重建,每次重建都会在Activity中重新创建WishlistRepository实例,导致Repository内的
wishListLiveData是全新的空实例 - Activity中通过判断
wishListLiveData.value == null触发请求,新LiveData自然满足该条件,从而重复调用API
解决方案
1. 将Repository改为单例模式
避免Activity重建时重复创建Repository,确保ViewModel始终复用同一个实例,保留LiveData的状态:
class WishlistRepository private constructor(private val context: Context) { companion object { @Volatile private var INSTANCE: WishlistRepository? = null fun getInstance(context: Context): WishlistRepository { return INSTANCE ?: synchronized(this) { val instance = WishlistRepository(context.applicationContext) INSTANCE = instance instance } } } // 原有LiveData与API调用逻辑保持不变 private val wishListLiveData = MutableLiveData<Resource<WishlistModel>>() val wishLiveData: LiveData<Resource<WishlistModel>> get() = wishListLiveData fun getWishlistApiCall(params: Map<String, String>) { // 原逻辑代码不变 } }
2. 调整Activity中Repository的获取方式
不再每次创建新实例,改为获取单例:
// 替换原repository创建代码 val repository = WishlistRepository.getInstance(activity) wishlistViewModel = ViewModelProvider( this, WishlistViewModelFactory(repository) )[WishlistViewModel::class.java]
3. 让ViewModel管理请求状态
新增标志位控制请求触发逻辑,避免Activity重复发起请求:
class WishlistViewModel(private val repository: WishlistRepository) : ViewModel() { val wishListLiveData: LiveData<Resource<WishlistModel>> get() = repository.wishLiveData private var hasInitiatedRequest = false // 仅在首次或无有效数据时发起请求 fun loadWishListIfNeeded(params: Map<String, String>) { if (!hasInitiatedRequest || wishListLiveData.value !is Resource.Success) { hasInitiatedRequest = true repository.getWishlistApiCall(params) } } // 删除成功后强制刷新数据 fun refreshWishList(params: Map<String, String>) { repository.getWishlistApiCall(params) } }
4. 修改Activity的请求触发逻辑
去掉原有的wishListLiveData.value == null判断,改为调用ViewModel的方法:
if (preferenceUtils.getPrefBoolean(Constants.IS_LOGGED_IN)) { val params = mutableMapOf<String, String>().apply { this["customer_id"] = preferenceUtils.getPreString(Constants.USER_ID) this["store"] = preferenceUtils.getPreInt(Constants.STORE).toString() } wishlistViewModel.loadWishListIfNeeded(params) } else { val intent = Intent(activity, LoginActivity::class.java) intent.putExtra("fromScreen", 2) startActivity(intent) }
5. 调整删除成功后的刷新逻辑
替换原prepareParams()调用,改为触发ViewModel的刷新方法:
// 删除成功后的回调中替换原有prepareParams() val params = mutableMapOf<String, String>().apply { this["customer_id"] = preferenceUtils.getPreString(Constants.USER_ID) this["store"] = preferenceUtils.getPreInt(Constants.STORE).toString() } wishlistViewModel.refreshWishList(params)
额外优化提示
- 避免Repository持有Activity引用,改用ApplicationContext防止内存泄漏(已在单例实现中处理)
- 可使用
ViewModel的SavedStateHandle持久化请求状态,进一步增强配置变更后的状态稳定性 - 可为API请求添加防抖逻辑,避免短时间内重复发起相同请求
内容的提问来源于stack exchange,提问作者Milan Gajera
相关产品推荐
相关产品推荐

