英文:
Ui flickering when reading value from database using room
问题
ViewModel
class FlashcardViewModel(private val flashcardsRepository: FlashcardsRepository): ViewModel() {
val timeoutMillis = 5_000L
fun getFlashcardsFilteredByTopic(topic: String): StateFlow<List<Flashcard>> {
val flashcardUiState: StateFlow<List<Flashcard>> = flashcardsRepository.getFlashcardsStreamFilteredByTopic(topic = topic)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(timeoutMillis),
initialValue = listOf(Flashcard())
)
return flashcardUiState
}
}
用于显示闪卡的可组合函数
@Composable
fun FlashcardScreen(
topic: String
) {
val viewModel: FlashcardViewModel = viewModel(factory = Factory)
val flashcardUiState by viewModel.getFlashcardsFilteredByTopic(topic).collectAsState()
var currentIndex by rememberSaveable{ mutableStateOf(0) }
val currentFlashcard = flashcardUiState[currentIndex]
Flashcard(flashcard = currentFlashcard)
}
@Composable
fun Flashcard(flashcard: Flashcard) {
Text(
text = flashcard.question
)
Text(
text = flashcard.answer,
)
}
英文:
My code is supposed to use room to get flashcards filtered by topic and then display it. The flashcard does get displayed but the text keeps on flickering. Any help would be appreciated.
ViewModel
class FlashcardViewModel(private val flashcardsRepository: FlashcardsRepository): ViewModel() {
val timeoutMillis = 5_000L
fun getFlashcardsFilteredByTopic(topic: String): StateFlow<List<Flashcard>> {
val flashcardUiState: StateFlow<List<Flashcard>> = flashcardsRepository.getFlashcardsStreamFilteredByTopic(topic = topic)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(timeoutMillis),
initialValue = listOf(Flashcard())
)
return flashcardUiState
}
}
Composable functions to display the flashcard
@Composable
fun FlashcardScreen(
topic: String
) {
val viewModel: FlashcardViewModel = viewModel(factory = Factory)
val flashcardUiState by viewModel.getFlashcardsFilteredByTopic(topic).collectAsState()
var currentIndex by rememberSaveable{ mutableStateOf(0) }
val currentFlashcard = flashcardUiState[currentIndex]
Flashcard(flashcard = currentFlashcard)
}
@Composable
fun Flashcard(flashcard: Flashcard) {
Text(
text = flashcard.question
)
Text(
text = flashcard.answer,
)
}
答案1
得分: 2
你在每次重新组合时都在调用 getFlashcardsFilteredByTopic
。该函数会创建一个新的 StateFlow
,其默认值是一个空卡片(listOf(Flashcard())
),并且可能会执行数据库查询并使用结果更新流,从而触发重新组合并重新开始整个过程。
一个可能的解决方案是将 topic
放在 ViewModel 中,然后像这样做:
// FlashcardViewModel
val topic = MutableStateFlow("")
val flashCards = topic.flatMapLatest { topic ->
flashcardsRepository.getFlashcardsStreamFilteredByTopic(topic = topic)
}.stateIn(...)
或者你可以在 ViewModel 中使用 remember
来记住你创建的流,这样只有当主题发生变化时才会调用 getFlashcardsFilteredByTopic
:
// FlashcardScreen
val flashCardsFlow = remember(topic) {
viewModel.getFlashcardsFilteredByTopic(topic)
}
val flashcardUiState by flashCardsFlow.collectAsState()
英文:
You are calling getFlashcardsFilteredByTopic
in each recomposition. This function creates new StateFlow
with default value of empty card (listOf(Flashcard())
) and presumably executes the database query and updates the flow with the result, which triggers the recomposition and it all starts again.
One possible solution would be to put the topic
in the ViewModel and do something like this:
// FlashcardViewModel
val topic = MutableStateFlow("")
val flashCards = topic.flatMapLatest { topic ->
flashcardsRepository.getFlashcardsStreamFilteredByTopic(topic = topic)
}.stateIn(...)
Or you can remember
the flow you create in ViewModel, this will only call getFlashcardsFilteredByTopic
when the topic changes:
// FlashcardScreen
val flashCardsFlow = remember(topic) {
viewModel.getFlashcardsFilteredByTopic(topic)
}
val flashcardUiState by flashCardsFlow.collectAsState()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论