首页 > 解决方案 > Kotlin & flow & MVVM -> 切换片段时观察者多次触发

问题描述

我正在学习流程并在我的项目中实施它们,但我不确定我是否理解了所有内容。

这是我的模型

data class ResultResponse (
    @field:Json(name = "count") val count : Int?,
    @field:Json(name = "favorites") val "favorites") : List<Favorite>?
)

这是我的服务

@GET("...")
suspend fun getFavorites(@Path("visitor") visitor: String) : Response<ApiModel<ResultResponse>>

这是我的存储库

suspend fun getFavorites(visitor: String) = flow {
    emit(apiCall { api.getFavorites(visitor) })
}.onStart {
    emit(State.loading())
}

apiCall 在哪里

suspend fun <T> apiCall(call: suspend () -> Response<T>): State<T>

这是我的视图模型

private val parentJob = Job()

private val coroutineContext: CoroutineContext
    get() = parentJob + Dispatchers.Default

private val scope = CoroutineScope(coroutineContext)

private val repository = FavoriteRepository(Api.favoriteService)

private val _favorites = MutableLiveData<State<ApiModel<ResultResponse>>>()

val favorites: LiveData<State<ApiModel<ResultResponse>>>
    get() = _favorites

fun fetchFavorites() {
    scope.launch {
        repository.getFavorites(Preferences.visitor).collect {
            _favorites.postValue(it)
        }
    }
}

这是我的片段

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    observer()
}

override fun onResume() {
    super.onResume()

    favoriteViewModel.fetchFavorites()
}

private fun observer() {
    favoriteViewModel.favorites.observe(viewLifecycleOwner) { state ->
        when (state) {
            is State.Loading -> doSomethingOnLoadingState()
            is State.Success -> doSomethingOnSuccessState(state)
            is State.Error -> doSomethingOnErrorState(state)
        }
    }
}

问题是当我切换片段并回到这个片段时,它再次观察到最后一个状态,所以我得到了 State.Success 然后 State.Loading 然后 State.Success 触发。我尝试使用事件和 getContentIfNotHandled() 来解决它?但它没有改变任何东西。

第二个问题是我做对了吗,这是目前最好的方法吗?

标签: androidkotlinmvvmflow

解决方案


一切都按预期工作。返回片段后,您的 LiveData 仍保持先前的 Success 状态,然后从存储库中获取另一个 Loading 和 Success。

对我来说,loading在你的存储库中有一个状态似乎是不对的。我会将其移至 ViewModel,然后仅在必要时发出它(如果您确实想在视图中显示它),例如通过检查当前 liveData 状态或在 fetchFavourites 方法中使用布尔标志。

至于第二个问题 - 一如既往 - 这取决于。我个人不会为单个 api 调用创建流程,而是更愿意使用挂起函数。


推荐阅读