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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 04:36:16