Ich habe eine Film-App, die mit Jetpack Compose erstellt wurde. Darin zeige ich die vom Benutzer ausgewählten Lieblingsfilme. Die Favoriten sollten in der Benutzeroberfläche einwandfrei vorhanden sein, aber wenn ich ein Element aus der Benutzeroberfläche lösche, wird die Benutzeroberfläche nicht sofort neu organisiert, um die Änderungen widerzuspiegeln. was zu tun?
Das ist meine Benutzeroberfläche
@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)))} ) } }
Das ist mein Ansichtsmodell
@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() } }
Das Problem wird sehr deutlich, wenn man sich die schriftliche Verwendung von _favs
ansieht:
Nur getfavmovies
wird es aktualisieren.
Während das klingt wie „Sie sollten Ihren UI-Status in der Löschfunktion aktualisieren“, möchte ich eine alternative Lösung vorschlagen:
Nutzen Sie die Kraft von room
+ flows
!
Definieren Sie zunächst loadingstate
im Ansichtsmodell, das als Stream gespeichert wird:
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)
Ändern Sie dann die getfavmovies()
-Funktion, um diesen Mechanismus zu verwenden:
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!!) } } }
Kombinieren Sie abschließend Ihren Status und Ihre Daten, um Magie zu verwirklichen. Dies wird automatisch aktualisiert, sobald sich einer von ihnen ändert :)
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 } }
Haftungsausschluss: Möglicherweise sind darin Rechtschreibfehler enthalten, ich habe keine Idee zur Hand
Beenden wir diese Antwort, indem wir den Code verbessern:
Vermeiden Sie die Verwendung von =
für Funktionen, die nichts zurückgeben (=
用于不返回任何内容的函数(getfavmovies
、insertmovie
、deletemovies
)。否则,你会例如期望 getfavmovies
, insertmovie
, deletemovies
). Andernfalls würden Sie beispielsweise erwarten, dass
remember { mutablestateof(movieviewmodel.getfavmovies()) }
并没有真正的 remember
任何东西,是吗?这太令人恼火了。我建议将其移至 viewmodel 中: init { movieviewmodel.getfavmovies() }
val uistates = movieviewmodel.favs.collectasstate()
:命名意味着这是多个 ui 状态,请使用单数; uistates
类本身也是如此。另外,如果这里直接使用“.value”,可以跳过这里的重新声明:when(val currentstate = uistates.value)
mutablelist9fed9bb6bc0c66d7a13f33ab448de4c5
。对 ui 状态使用可变值是一个坏主意,例如它可能会混淆您的 stateflow
Ihr Uistate enthält . Vermeiden Sie diese Situation unbedingt. Benutzen Sie einfach die einfache alte Liste :) https://www.php.cn/link/ff685590317f1330efc73f396ac92cd7
collectasstatewithlifecycle()
而不是 collectasstate()
Verwenden Sie . Siehe https://medium.com/androiddevelopers/sumption-flows – sicher in jetpack-compose-cde014d0d5a3
repoimpl
Sie sollten im Ansichtsmodell auf keinen Fall auf
Es ist eine gute Idee, ein Screen-Composeable zu definieren, es erfordert kein Ansichtsmodell, sondern nur Daten, ähnlich wie 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 }
Das obige ist der detaillierte Inhalt vonDie Benutzeroberfläche wurde nach dem Löschen aller Elemente im Jetpack mithilfe der Raumdatenbank nicht neu zusammengesetzt. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!