Reputation: 380
I'm working on an app that tracks cars at a valet. My issue is that upon successfully adding a new car to the list, it navigates back to the list view but the added car is not shown in the list. Below is a simplified version of my code using dummy data. I'd appreciate any insight into this.
data class Car(
val id: String,
val model: String,
val status: String // "Parked" or "Requested"
)
@HiltViewModel
class CarViewModel : ViewModel() {
val carList = mutableStateListOf<Car>()
init {
// Initially populate the list with some dummy data
carList.addAll(listOf(
Car("1", "Car Model 1", "Parked"),
Car("2", "Car Model 2", "Requested")
))
}
// function to add a new car
fun addCar(car: Car) {
carList.add(car)
}
}
@Composable
fun CarList(viewModel: CarViewModel = hiltViewModel()) {
Column {
// List to display cars
LazyColumn {
items(items = viewModel.carList, key = { car -> car.id }) { car ->
Text(text = "${car.model} - ${car.status}")
}
}
}
}
@Composable
fun CheckInScreen(navController: NavHostController, viewModel: CarViewModel = hiltViewModel()) {
// Simplified form state
var carModel by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
Text(text = "Add New Car", style = MaterialTheme.typography.h6)
Spacer(modifier = Modifier.height(16.dp))
// Simple text field for car model
OutlinedTextField(
value = carModel,
onValueChange = { carModel = it },
label = { Text("Car Model") }
)
Spacer(modifier = Modifier.height(16.dp))
// Button to add car
Button(onClick = {
if (carModel.isNotEmpty()) {
val newCar = Car(id = UUID.randomUUID().toString(), model = carModel, status = "Parked")
viewModel.addCar(newCar)
navController.popBackStack() // navigates back to the car list
}
}) {
Text("Add Car")
}
}
}
The flow looks like this: car list -> check in screen (add car) -> car list. Thank you!
Upvotes: 0
Views: 63
Reputation: 15763
You have multiple instances of CarViewModel
. One is displayed in CarList
and each time CheckInScreen
is called (which might occur much more often than just when you navigate to it) another one is created. Since they are sparate instances, modifying carList
in one instance doesn't affect carList
in the other instances.
What you want is that your composables all share the same instance of the view model.
There are several ways to achieve this:
val viewModel: CarViewModel by viewModels()
.ViewModelStoreOwner
by setting set first parameter of viewModel()
to the activity (or something else that should share the same view model).val viewModel: CarViewModel = hiltViewModel()
in each composable where you need it. It is good practice, though, to hoist it at least to the screen level and only pass down the properties and functions that each composable actually needs.I would prefer the last option, though you would need to set up Hilt first.
Upvotes: 1