Clément Cardonnel
07/28/2022, 10:17 AM@Composable
fun ParkView(parkId: String, viewModel: ParkViewModel = ParkViewModel(context = LocalContext.current, parkId = parkId)) {}
But when there’s a change inside my composable, I think it gets recomposed and alongside it my view model is recreated. For example, I have a TabRow which updates the view model when its onClick lambda is triggered.
viewModel.tabIndex.value = index
This triggers an infinite loop, where my viewModel is recreated indefinitely.
Where the view model should be instantiated or at least, how can I avoid this infinite loop? I’m providing an example of view and its viewModel in the replies.
And of course, thank you very much for your answers 😌@Composable
fun ParkView(parkId: String, viewModel: ParkViewModel = ParkViewModel(context = LocalContext.current, parkId = parkId)) {
val park by viewModel.park.collectAsState()
val scrollState = rememberScrollState()
val tabIndex by viewModel.tabIndex.collectAsState()
val tabTitles = listOf("1", "2")
Column(modifier = Modifier.scrollable(scrollState, Orientation.Vertical)) {
if (park != null) {
val park = park!!
Text(text = park.title ?: "")
TabRow(selectedTabIndex = tabIndex) { // 3.
tabTitles.forEachIndexed { index, title ->
Tab(selected = tabIndex == index, // 4.
onClick = { viewModel.tabIndex.value = index },
text = { Text(text = title) }) // 5.
}
}
when (tabIndex) { // 6.
0 -> Text("1 content")
1 -> Text("2 content")
}
}
}
}
class ParkViewModel(
val context: Context,
val parkId: String
): ViewModel() {
private val _park = MutableStateFlow<QLPark?>(null)
val park: StateFlow<QLPark?> get() = _park
val tabIndex = MutableStateFlow<Int>(value = 0)
init {
viewModelScope.launch {
fetchPark()
}
}
private suspend fun fetchPark() {
// This is an asynchronous network call, and ultimately what it does is getting a new park and setting the park property
_park.value = newPark
}
}
Daniel Žůrek
07/28/2022, 11:39 AMHuan
07/28/2022, 11:43 AMan example using hilt
@HiltViewModel
class ParkViewModel @Inject constructor(
): ViewModel() {
@Composable
fun ParkView(parkId: String, viewModel: ParkViewModel = hiltViewModel())
Keep in mind that you also have to inject the parameters to the viewmodel. For example, the context can be injected using
@ApplicationContext val context: Context,
On the other hand for the parkId, you can use SaveStateHandle if you need it
https://stackoverflow.com/questions/69145407/how-to-pass-id-and-application-to-a-viewmodel-viewmodelfactory-in-jetpack-composClément Cardonnel
07/28/2022, 11:57 AMColton Idle
07/29/2022, 4:15 AMClément Cardonnel
07/29/2022, 10:40 AM