Kotlin & flow & MVVM -> 切换片段时观察者触发多次
Kotlin & flow & MVVM -> observer triggered multiple time when switch fragment
我正在学习流程并在我的项目中实施它们,但我不确定我是否理解所有内容。
这是我的模型
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。我尝试使用 Event and getContentIfNotHandled()? 解决它,但它没有改变任何东西。
第二个问题是我做对了吗,这是目前最好的方法吗?
一切正常。返回片段后,您的 LiveData 仍保持先前的 Success 状态,然后从存储库中获取另一个 Loading 和 Success。
对我来说,在您的存储库中有一个 loading
状态似乎不对。我会将它移动到 ViewModel,然后仅在必要时发出它(如果你真的想在视图中显示它),例如通过检查当前 liveData 状态或在 fetchFavourites 方法中使用布尔标志。
至于第二个问题——一如既往——视情况而定。我个人不会为单个 api 调用创建流程,而是宁愿使用暂停功能。
我正在学习流程并在我的项目中实施它们,但我不确定我是否理解所有内容。
这是我的模型
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。我尝试使用 Event and getContentIfNotHandled()? 解决它,但它没有改变任何东西。
第二个问题是我做对了吗,这是目前最好的方法吗?
一切正常。返回片段后,您的 LiveData 仍保持先前的 Success 状态,然后从存储库中获取另一个 Loading 和 Success。
对我来说,在您的存储库中有一个 loading
状态似乎不对。我会将它移动到 ViewModel,然后仅在必要时发出它(如果你真的想在视图中显示它),例如通过检查当前 liveData 状态或在 fetchFavourites 方法中使用布尔标志。
至于第二个问题——一如既往——视情况而定。我个人不会为单个 api 调用创建流程,而是宁愿使用暂停功能。