J'ai une application de film créée à l'aide de Jetpack Compose. J'y montre les films préférés sélectionnés par l'utilisateur. Les favoris devraient parfaitement exister dans l'interface utilisateur, mais lorsque je supprime un élément de l'interface utilisateur, l'interface utilisateur ne se réorganise pas immédiatement pour refléter le changement. ce qu'il faut faire?
C'est mon interface utilisateur
@composable fun favscreen( movieviewmodel: movieviewmodel ) { remember { mutablestateof(movieviewmodel.getfavmovies()) } val shouldshowdialog = remember { mutablestateof(false) } val uistates = movieviewmodel.favs.collectasstate() column { row { text( text = "fav movies", fontsize = 25.sp, fontfamily = fontfamily(font(r.font.nsb)), modifier = modifier.padding(20.dp).weight(1f) ) iconbutton(onclick = { shouldshowdialog.value = true }) { icon(icons.filled.delete, contentdescription = "") } } when(val currentstate = uistates.value){ is movieviewmodel.uistates.loading -> { box(modifier = modifier.fillmaxsize(), contentalignment = alignment.center) { circularprogressindicator() } } is movieviewmodel.uistates.favs -> { val data = currentstate.data if(data.isempty()){ box(modifier = modifier.fillmaxsize(), contentalignment = alignment.center) { text( text = "no fav movies", fontsize = 25.sp, fontfamily = fontfamily(font(r.font.nsb)), modifier = modifier.padding(20.dp)) } } else { lazycolumn(){ items(data){ fav -> row(modifier = modifier .padding(20.dp) .fillmaxwidth() .clip(roundedcornershape(16.dp)) .background(color = color.darkgray)) { asyncimage( model = utils.image_url + fav.imageurl, contentdescription = "", contentscale = contentscale.crop, filterquality = filterquality.high, modifier = modifier .width(150.dp) .height(150.dp)) column(modifier = modifier.padding(20.dp)) { text( text = fav.title!!, fontsize = 20.sp, fontfamily = fontfamily(font(r.font.nsb))) text( text = fav.rating.tostring() + "/10 imdb", fontsize = 15.sp, fontfamily = fontfamily(font(r.font.nsb))) text( text = "movie id : #" + fav.movieid, fontsize = 15.sp, fontfamily = fontfamily(font(r.font.nsb))) } } } } } } is movieviewmodel.uistates.error -> { box(modifier = modifier.fillmaxsize(), contentalignment = alignment.center){ text( text = "no fav movies", fontsize = 25.sp, fontfamily = fontfamily(font(r.font.nsb)), modifier = modifier.padding(20.dp)) } } else -> {} } } if (shouldshowdialog.value){ alertdialog( ondismissrequest = { shouldshowdialog.value = false }, confirmbutton = { textbutton(onclick = { movieviewmodel.deletemovies() shouldshowdialog.value = false }) { text(text = "proceed", fontfamily = fontfamily(font(r.font.nsm))) } }, dismissbutton = { textbutton(onclick = { shouldshowdialog.value = false }) { text(text = "cancel", fontfamily = fontfamily(font(r.font.nsm))) } }, shape = roundedcornershape(16.dp), text = { text(text = "favs deletion",fontfamily = fontfamily(font(r.font.nsb)))}, title = { text(text = "do you want to delete all fav movies ?", fontfamily = fontfamily(font(r.font.nsb)))} ) } }
C'est mon modèle de vue
@HiltViewModel class MovieViewModel @Inject constructor( private val movieRepoImpl: MovieRepoImpl ) : ViewModel() { private val _favs : MutableStateFlow<UiStates> = MutableStateFlow(UiStates.INITIAL) val favs get() = _favs.asStateFlow() // MOVIE DAO fun getFavMovies() = viewModelScope.launch { try { _favs.value = UiStates.LOADING movieRepoImpl.getFavs().collectLatest { _favs.value = UiStates.FAVS(it) } } catch (ex : Exception){ _favs.value = UiStates.ERROR(ex.localizedMessage!!) } } fun insertMovie(favModel: FavModel) = viewModelScope.launch { movieRepoImpl.insertFav(favModel) } fun deleteMovies() = viewModelScope.launch { movieRepoImpl.deleteAllMovies() } sealed class UiStates { object LOADING : UiStates() data class FAVS(val data : MutableList<FavModel>) : UiStates() data class ERROR(val error : String) : UiStates() object INITIAL : UiStates() } }
Le problème devient très évident lorsque l'on regarde l'utilisation écrite de _favs
:
Seul getfavmovies
le mettra à jour.
Bien que cela ressemble à "vous devriez mettre à jour l'état de votre interface utilisateur dans la fonction de suppression", j'aimerais proposer une solution alternative :
Exploitez le pouvoir de room
+ flows
!
Définissez d'abord loadingstate
dans le modèle de vue, qui sera stocké sous forme de flux :
sealed class loadingstate { object loading : loadingstate() data class success : loadingstate() data class error(val error : string) : loadingstate() object initial : loadingstate() } private val loadingstate = mutablestateflow<loadingstate>(initial)
Ensuite, changez la fonction getfavmovies()
pour utiliser ce mécanisme :
fun getfavmovies() { viewmodelscope.launch { try { _loadingstate.value = loadingstate.loading movierepoimpl.loadfavs() // a function which triggers e.g. a network call to actually load your movies _loadingstate.value = loadingstate.success } catch (ex: exception) { _loadingstate.value = loadingstate.error(ex.localizedmessage!!) } } }
Enfin, combinez votre statut et vos données pour que la magie opère. Cela sera automatiquement mis à jour une fois que l'un d'eux aura changé :)
val favs: flow<uistates> = combine( movierepoimpl.getmovies(), loadingstate ) { movies, loadingstate -> when (loadingstate) { is loadingstate.loading -> uistates.loading is loadingstate.success -> uistates.success(movies) is loadingstate.error -> uistates.error(error) is loadingstate. initial -> uistates.initial } }
Avertissement : il peut y avoir des fautes d'orthographe, je n'en ai pas d'idée sous la main
Terminons cette réponse en améliorant le code :
Évitez d'utiliser =
pour les fonctions qui ne renvoient rien (=
用于不返回任何内容的函数(getfavmovies
、insertmovie
、deletemovies
)。否则,你会例如期望 getfavmovies
, insertmovie
, deletemovies
). Sinon, vous vous attendriez par exemple à ce que
remember { mutablestateof(movieviewmodel.getfavmovies()) }
并没有真正的 remember
任何东西,是吗?这太令人恼火了。我建议将其移至 viewmodel 中: init { movieviewmodel.getfavmovies() }
val uistates = movieviewmodel.favs.collectasstate()
:命名意味着这是多个 ui 状态,请使用单数; uistates
类本身也是如此。另外,如果这里直接使用“.value”,可以跳过这里的重新声明:when(val currentstate = uistates.value)
mutablelist<favmodel>
。对 ui 状态使用可变值是一个坏主意,例如它可能会混淆您的 stateflow
Votre état contient . Assurez-vous d'éviter cette situation. Utilisez simplement l'ancienne liste :) https://www.php.cn/link/ff685590317f1330efc73f396ac92cd7
collectasstatewithlifecycle()
而不是 collectasstate()
Utilisez . Voir https://medium.com/androiddevelopers/smoking-flows - en toute sécurité dans jetpack-compose-cde014d0d5a3
repoimpl
Vous ne devez absolument pas accéder à
C'est une bonne idée de définir un screen-composable, cela ne nécessite pas de modèle de vue, juste des données, similaire à https://developer.android.com/jetpack/compose/state#state-hoisting
:.🎜
@Composable private fun FavScreen( val viewModel: MovieViewModel, ) { FawScreen( uiState = viewModel.fav.collectAsStateWithLifecycle().value, shouldShowDialog = viewModel.shouldShowDialog.collectAsStateWithLifecycle().value ) } @Composable private fun FavScreen( val uiState: UiStates, val shouldShowDialog: Boolean ) { // your current ui }
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!