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

如何在Activity中重置ViewModel并切换Retrofit请求BaseUrl

问题:MVVM中切换Retrofit BaseUrl无效,如何重置ViewModel状态?

现有代码实现

ViewModel中的请求方法

fun fetchStrings(lang: String, callBack: (res: JsonObject?) -> Unit) {
    job = CoroutineScope(Dispatchers.IO).launch {
        val array = JsonArray().apply { strings.forEach { item -> add(item) } }
        val jsonObject = JsonObject().apply {
            addProperty("lang", lang)
            add("ids", array)
        }
        val response = mainRepository.getStrings(jsonObject)
        withContext(Dispatchers.Main) {
            if (response.isSuccessful) {
                callBack.invoke(response.body())
            } else {
                callBack.invoke(null)
            }
        }
    }
}
fun getUserFiles(requestBody: RequestBody? = null, callBack: (res: Any) -> Unit) {
    job = CoroutineScope(Dispatchers.IO).launch {
        val response = requestBody?.let { mainRepository.getUserFiles(it) }
        withContext(Dispatchers.Main) {
            if (response?.isSuccessful == true) {
                callBack.invoke(response.body()!!)
            } else {
                response?.message()?.let { callBack.invoke(it) }
            }
        }
    }
}

MainRepository代码

class MainRepository constructor(private val retrofitService: RetrofitService) {
    suspend fun getUserFiles(requestBody: RequestBody) = retrofitService.getUserFiles(requestBody)
    suspend fun getStrings(jsonObject: JsonObject) = retrofitService.getStrings(jsonObject)
}

RetrofitService单例实现

companion object {
    var retrofitService: RetrofitService? = null
    fun getInstance(mint: Boolean): RetrofitService {
        var isMint = true
        val client = OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.MINUTES)
            .callTimeout(10, TimeUnit.MINUTES)
            .writeTimeout(10, TimeUnit.MINUTES)
            .readTimeout(10, TimeUnit.MINUTES)
            .connectionPool(ConnectionPool(0, 5, TimeUnit.SECONDS))
            .dispatcher(Dispatcher().apply {
                maxRequests = 1
            })
            .protocols(listOf(Protocol.HTTP_1_1))
            .build()

        client.dispatcher.cancelAll()

        val retrofit = Retrofit.Builder()
            .baseUrl(if (mint) BuildConfig.MINT_URL else BuildConfig.API_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        retrofitService = retrofit.create(RetrofitService::class.java)

        return retrofitService!!
    }
}

问题现象

在Activity中修改RetrofitService.getInstance(false)的参数为true/false时,BaseUrl并未切换。尝试过调用viewModelStoreOwner.viewModelStore.clear()清空ViewModel、修改BaseUrl判断逻辑、取消ViewModel协程等方法,均无效。目前只能通过新建独立ViewModel及对应Repository解决,想知道是否有在同一个ViewModelStoreOwner下重置ViewModel所有状态的方案。


解决方案

1. 修复Retrofit单例的逻辑错误

原单例代码中var isMint = true是冗余代码,且单例只会保留最后一次创建的实例,无法同时维护两个BaseUrl对应的Service。修改为分别存储两个实例:

companion object {
    private var mintRetrofitService: RetrofitService? = null
    private var regularRetrofitService: RetrofitService? = null

    fun getInstance(mint: Boolean): RetrofitService {
        return if (mint) {
            mintRetrofitService ?: createRetrofitInstance(true).also { mintRetrofitService = it }
        } else {
            regularRetrofitService ?: createRetrofitInstance(false).also { regularRetrofitService = it }
        }
    }

    private fun createRetrofitInstance(mint: Boolean): RetrofitService {
        val client = OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.MINUTES)
            .callTimeout(10, TimeUnit.MINUTES)
            .writeTimeout(10, TimeUnit.MINUTES)
            .readTimeout(10, TimeUnit.MINUTES)
            .connectionPool(ConnectionPool(0, 5, TimeUnit.SECONDS))
            .dispatcher(Dispatcher().apply {
                maxRequests = 1
            })
            .protocols(listOf(Protocol.HTTP_1_1))
            .build()

        val retrofit = Retrofit.Builder()
            .baseUrl(if (mint) BuildConfig.MINT_URL else BuildConfig.API_URL)
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        return retrofit.create(RetrofitService::class.java)
    }
}

2. 让ViewModel支持动态更新Repository

ViewModel构造时注入的Repository是固定的,需要提供方法允许替换内部的Repository:

class RequestsCore(private var mainRepository: MainRepository) : ViewModel() {
    // 新增方法:更新Repository
    fun updateRepository(newRepository: MainRepository) {
        this.mainRepository = newRepository
    }

    // 原有的fetchStrings、getUserFiles方法保持不变
}

在Activity中切换BaseUrl时:

// 创建新的RetrofitService和Repository
val newRetrofit = RetrofitService.getInstance(true)
val newRepo = MainRepository(newRetrofit)
// 更新ViewModel的Repository
viewVM.updateRepository(newRepo)

3. 完全重置ViewModel(同ViewModelStoreOwner下)

如果需要彻底重置ViewModel状态,先清空ViewModelStore再重新创建ViewModel:

// 清空当前ViewModelStoreOwner下的所有ViewModel
viewModelStore.clear()
// 用新的RetrofitService创建ViewModel
val newRetrofit = RetrofitService.getInstance(true)
val newRepo = MainRepository(newRetrofit)
val viewVM = ViewModelProvider(
    this,
    AppVMFactory(newRepo)
)[RequestsCore::class.java]

注意:viewModelStore.clear()会销毁所有关联的ViewModel,需确保其他ViewModel状态无需保留。之前调用无效可能是因为未重新创建ViewModel,或者ViewModel实例仍被其他引用持有。

4. 进阶方案:使用依赖注入框架

如果项目引入Hilt等依赖注入框架,可以通过绑定不同的RetrofitService实例,根据参数动态提供,实现更优雅的切换逻辑,无需手动管理实例和ViewModel更新。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 22:12:54