I'm working on a Jetpack Compose Android app that displays a list of trains. I have Screen A that shows a list of trains and Screen B that displays the details of a selected train. Each screen has its own ViewModel (using hiltViewModel()).
Here’s the flow:
- Screen A loads and fetches a list of trains via an API.
- User taps on a train.
- App navigates to Screen B (TrainDetailsScreen) to show the train's full info.
Question:
Where is the best place to trigger the API call to fetch full train details?
- In Screen A, before navigation and pass the data to B?
- Or let Screen B make its own API call using the train number/id?
What is the recommended pattern in MVVM + Jetpack Compose (each screen having its own ViewModel)?
Screen A (Train List)
@Composable
fun TrainListScreen(navController: NavController, viewModel: TrainListViewModel = hiltViewModel()) {
val state by viewModel.trainList.collectAsState()
LazyColumn {
items(state.trains) { train ->
Text(
text = train.name,
modifier = Modifier.clickable {
navController.navigate("trainDetail/${train.number}")
}
)
}
}
}
Navigation Setup
NavHost(navController, startDestination = "trainList") {
composable("trainList") { TrainListScreen(navController) }
composable(
"trainDetail/{trainNumber}",
arguments = listOf(navArgument("trainNumber") { type = NavType.StringType })
) { backStackEntry ->
val trainNumber = backStackEntry.arguments?.getString("trainNumber") ?: ""
TrainDetailScreen(trainNumber)
}
}
Screen B (Train Detail)
@Composable
fun TrainDetailScreen(
trainNumber: String,
viewModel: TrainDetailViewModel = hiltViewModel()
) {
val state by viewModel.trainDetail.collectAsState()
LaunchedEffect(trainNumber) {
viewModel.loadTrainDetail(trainNumber)
}
if (state.isLoading) {
CircularProgressIndicator()
} else {
Text("Train Name: ${state.train?.name}")
// show more details
}
}
Which screen should be responsible for the API call? Is LaunchedEffect the correct way to make api?