Kotlin

#android #kotlin #mvvm #flow

#Android #kotlin #mvvm #kotlin-flow

Вопрос:

Я изучаю потоки и внедряю их в свой проект, но я не уверен, что все понял.

Это моя модель

 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)
        }
    }
}
 

Проблема в том, что когда я переключаю фрагмент и возвращаюсь к этому, он снова наблюдает последнее состояние, поэтому я получил состояние.Затем укажите состояние успеха.Загрузка затем состояние.Срабатывает успешно. Я пытался решить это с помощью события и getContentIfNotHandled()? но это ничего не изменило.

И второй вопрос: правильно ли я все сделал, это лучший способ сделать это в настоящее время?

Комментарии:

1. fetchFavorites() срабатывает от onResume() и, как и ожидалось, каждый раз

2. Да, я хочу обновлять список каждый раз, когда пользователь открывает представление. Первый раз работает хорошо, во второй раз я заметил, что он несколько раз вызывал моего наблюдателя (предыдущее состояние новое состояние).

Ответ №1:

Все работает так, как ожидалось. После возврата к фрагменту ваши LiveData по-прежнему сохраняют предыдущее состояние успеха, затем получают другую загрузку и успех из репозитория.

Для меня наличие loading состояния в вашем репозитории кажется неправильным. Я бы переместил его в ViewModel, а затем отправил бы его только при необходимости (если вы действительно хотите показать его в поле зрения), например, путем проверки текущего состояния LiveData или с помощью логического флага в методе fetchFavourites.

Что касается второго вопроса — как всегда — это зависит. Я лично не стал бы создавать поток для одного вызова api, а предпочел бы использовать функцию приостановки.

Комментарии:

1. Но я не хочу удерживать предыдущее состояние, потому что оно срабатывает два раза в моей функции doSomethingOnSuccessState (состояние).