Android jetpack compose для наблюдения за живыми данными

#android #kotlin #state #android-mvvm #android-jetpack-compose

#Android #kotlin #состояние #android-mvvm #android-jetpack-compose

Вопрос:

У меня есть вопрос относительно использования observeAsState() для автоматического заполнения составного списка.

Мой композитный файл выглядит следующим образом

 @Composable
    fun getTopMovies() {
        val topMovies by movieListViewModel.getTopMovies().observeAsState()
        when (topMovies?.status) {
            Status.Error -> Text("error")
            Status.Loading -> {
                Log.d("JJJ", "Loading ")
                Text(text = "Loading")
            }
            Status.Success -> createMovieItemView(topMovies?.data?.results.orEmpty())
        }
    }
  

При этом используется MVVM для выполнения сетевого вызова для извлечения некоторого списка данных и возврата его обратно как livedata.

Проблема, с которой я сталкиваюсь, заключается в том, что она, похоже, застряла в бесконечном цикле. Если я не использую observeeAsState и просто использую обычный способ none composable, т.е.:

movieListViewModel.getTopMovies().observe(viewLifecycleOwner, Observer { ...}

он работает, как и ожидалось, и выполняется и завершается, как только ошибка или успех возвращаются из уровня репозитория / домена.

Это createMovieItemView ниже:

     @Composable
    private fun createMovieItemView(movieList: List<MovieItem>) {
        LazyColumnFor(items = movieList, itemContent = { movieItem ->
            MovieListItem(MovieItemData(movieItem.posterPath.orEmpty(),
                    movieItem.title.orEmpty(),
                    movieItem.releaseDate.orEmpty(),
                    "some genra", ""), picasso)

        })
    } 
  

для автоматического заполнения составного списка.

Мой композитный файл выглядит следующим образом

 @Composable
    fun getTopMovies() {
        val topMovies by movieListViewModel.getTopMovies().observeAsState()
        when (topMovies?.status) {
            Status.Error -> Text("error")
            Status.Loading -> {
                Log.d("JJJ", "Loading ")
                Text(text = "Loading")
            }
            Status.Success -> createMovieItemView(topMovies?.data?.results.orEmpty())
        }
    }
  

При этом используется MVVM для выполнения сетевого вызова для получения некоторого списка данных, а затем возвращает livedata.

Похоже, проблема в том, что она застряла в бесконечном цикле. Если я не использую observeeAsState и просто использую обычный способ none composable, т.е. movieListViewModel.getTopMovies().observe(viewLifecycleOwner, Observer { он работает как ожидалось, выполняется и завершается, как только ошибка или успех возвращаются из уровня репозитория / домена.

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

1. Я думаю, вам следует ознакомиться с механизмом MutableStateFlow / StateFlow, они работают лучше / проще с Jetpack Compose

2. Вот где я узнал об использовании наблюдений, как показано в моем коде выше

Ответ №1:

У меня была похожая проблема, и я решил ее, обернув getTopMovies внутри LaunchedEffect блока, и в итоге получилось что-то вроде этого:

 @Composable
fun MoviesScreen(onTimeout: () -> Unit) {
    val topMovies by viewModel.topMovies.observeAsState()

    LaunchedEffect(true) {
       movieListViewModel.getTopMovies().observeAsState()
    }
}
  

В то время как ViewModel будет выглядеть примерно так:

 class MoviesViewModel(): ViewModel {

   var _topMovies: MutableLiveData<List<Movies>> = mutableLiveDataOf(listOf())
   val topMovies: LiveData<List<Movies>>

   fun getTopMovies(){
      _topMovies.postValue(repository.getTopMovies())
   }
}
  

Обратите внимание, что это псевдокод для описания решения. Который вдохновлен примером rememberUpdatedState

Если getTopMovies используются совместные процедуры, это имеет побочные эффекты, поэтому LaunchedEffect необходимо, потому что составные файлы должны быть без побочных эффектов, как описано в разделе Побочные эффекты в Compose .