Saya mempunyai apl filem yang dibina menggunakan karang jetpack. Di dalamnya saya menunjukkan filem kegemaran yang dipilih oleh pengguna. Kegemaran harus wujud dalam UI dengan sempurna, tetapi apabila saya memadamkan item daripada UI, UI tidak segera menyusun semula untuk mencerminkan perubahan. apa yang perlu dilakukan
Ini UI saya
@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)))} ) } }
Ini adalah model pandangan saya
@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() } }
Masalahnya menjadi sangat jelas apabila anda melihat penggunaan bertulis _favs
:
Hanya getfavmovies
akan mengemas kininya.
Walaupun ini terdengar seperti "anda harus mengemas kini keadaan UI anda dalam fungsi padam", saya ingin mencadangkan penyelesaian alternatif:
Manfaatkan kuasa room
+ flows
!
Tentukan dahulu loadingstate
dalam model pandangan, yang akan disimpan sebagai strim:
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)
Kemudian, tukar fungsi getfavmovies()
untuk menggunakan mekanisme ini:
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!!) } } }
Akhir sekali, gabungkan status dan data anda untuk membuat keajaiban berlaku. Ini akan dikemas kini secara automatik apabila salah satu daripadanya berubah :)
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 } }
Penafian: Mungkin terdapat kesilapan ejaan dalam hal ini, saya tidak mempunyai idea yang berguna
Mari tamatkan jawapan ini dengan menambah baik kod:
Elakkan menggunakan =
untuk fungsi yang tidak mengembalikan apa-apa (=
用于不返回任何内容的函数(getfavmovies
、insertmovie
、deletemovies
)。否则,你会例如期望 getfavmovies
, insertmovie
, deletemovies
). Jika tidak, anda akan menjangkakan
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
Uistate anda mengandungi . Pastikan anda mengelakkan situasi ini. Hanya gunakan senarai lama yang biasa :) https://www.php.cn/link/ff685590317f1330efc73f396ac92cd7
collectasstatewithlifecycle()
而不是 collectasstate()
Gunakan . Lihat https://medium.com/androiddevelopers/consuming-flows - selamat dalam jetpack-compose-cde014d0d5a3
repoimpl
Anda semestinya tidak boleh mengakses
Adalah idea yang baik untuk mentakrifkan yang boleh digubah skrin, ia tidak memerlukan model pandangan, hanya data, serupa dengan 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 }
Atas ialah kandungan terperinci UI tidak dipasang semula selepas memadamkan semua item dalam jetpack menggunakan pangkalan data bilik. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!