I am working with Compose Desktop. I have created a ViewModel class that is emitting some states as follows
internal class ImportViewModel(private val dbHelper: FirestoreHelper) {
private val scope = CoroutineScope(Dispatchers.Default)
private val uiState = MutableStateFlow<ImportUiState>(InitialState)
fun uiState() = uiState as StateFlow<ImportUiState>
fun beginImport(filePath: String) {
scope.launch {
try {
update("Before Delay")
delay(100)
update("Delay 1")
delay(100)
update("Delay 2")
delay(100)
update("Delay 3")
delay(100)
update("Delay 4")
delay(100)
update("Delay 5")
} catch (exception: Exception) {
println(exception.stackTrace)
update(exception.localizedMessage)
}
Where update
method is defined as follows
private fun update(text: String) {
println(text)
scope.launch {
uiState.emit(ProgressState(text))
}
}
I am collecting this StateFlow
in my composable as follows
@Composable
fun ImportTab() {
var progressText by remember { mutableStateOf("") }
val viewModel = ImportViewModel(FirestoreHelper)
val uiState = viewModel.uiState().collectAsState().value
Column(modifier = Modifier.padding(24.dp)) {
Button(onClick = {
viewModel.beginImport("")
}) {
Text("Begin Import")
}
if (uiState is ProgressState) {
progressText = uiState.status
}
if (progressText.isNotEmpty()) {
Text(text = progressText)
}
}
}
The problem is in UI I cannot get progressText
to get reflected after the first emission. I can see proper text in the console. I have tried playing around with Dispatchers
and working with uiState.status
directly instead of progressText
but no luck.
CodePudding user response:
Problem seems to be this line
val viewModel = ImportViewModel(FirestoreHelper)
ViewModel
probably being is recreated on every recomposition. Injecting it in the Composable
method fixes the problem for me.
@Composable
internal fun ImportTab(viewModel: ImportViewModel) {
..
}
Still not sure the best way to inject such dependencies in a Composable
method though.
CodePudding user response:
If you're using Android, you can use view models as showed in documentation.
In Compose for Desktop these are not available at the moment.
To save a view model between recomposition, you can use remember
. As far as I know Desktop doesn't have configuration changes like Android rotations, so remember
value should live until the view is in the view tree.
val viewModel = remember { ImportViewModel(FirestoreHelper) }