In the Add Shopping List item screen, I have a Modal Sheet
with options to take a camera snapshot or choose an image from the gallery. In this screen, I'm prepopulating Textfields
either from a shared ViewModel
or from Navigation
arguments. The issue I'm having is that when I take a photo or pick from the gallery, sometimes the LaunchedEffect
code block randomly executes and causes the TextFields
to be reset. However, the LaunchedEffect
always executes for the first time upon the composable entering the composition, as intended. What could be wrong with the code?
Main Activity NavHost
@Composable
fun ShoppingListApp(navController: NavHostController) {
LockScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
val sharedViewModel: SharedViewModel = hiltViewModel()
AnimatedNavHost(
navController = navController, startDestination = NavScreens.MainScreen.route,
enterTransition = { EnterTransition.None },
exitTransition = { ExitTransition.None }
) {
composable(
route = NavScreens.MainScreen.route,
) {
MainScreen(navController)
}
composable(
route = NavScreens.ShoppingListScreen.route
) {
val viewModel: ShoppingListScreenViewModel = hiltViewModel()
ShoppingListScreen(navController, viewModel, sharedViewModel)
}
composable(
route = NavScreens.AddItemScreen.route + "?id={id}&name={name}&category={category}",
arguments = listOf(
navArgument("id") {
type = NavType.LongType
defaultValue = 0L
},
navArgument("name") {
type = NavType.StringType
defaultValue = ""
},
navArgument("category") {
type = NavType.StringType
defaultValue = ""
}
)
) { entry ->
val addShoppingListScreenviewModel: AddShoppingListItemScreenViewModel = hiltViewModel()
AddItemScreen(
name = entry.arguments?.getString("name")!!,
category = entry.arguments?.getString("category")!!,
navController = navController,
addShoppingListItemScreenViewModel = addShoppingListScreenviewModel,
sharedViewModel = sharedViewModel
)
}
}
}
Shared ViewModel
class SharedViewModel: ViewModel() {
private val _item = mutableStateOf(ShoppingListItem())
private val _isEdit = mutableStateOf(false)
val item: State<ShoppingListItem>
get() = _item
val isEdit: State<Boolean>
get() = _isEdit
fun setState(stateToEdit: String, stateValue: Any?){
var item = _item.value
var isEdit = _isEdit.value
when (stateToEdit) {
"ShoppingListItem" -> item = stateValue as ShoppingListItem
"IsEdit" -> isEdit = stateValue as Boolean
}
_item.value = item
_isEdit.value = isEdit
}
}
Add Item Composable
@Composable
fun AddItemScreen(
navController: NavHostController,
addShoppingListItemScreenViewModel: AddShoppingListItemScreenViewModel,
sharedViewModel: SharedViewModel,
name: String = "",
category: String = "",
) {
val shoppingListItem = sharedViewModel.item.value
LaunchedEffect(Unit) {
if (name.isNotEmpty() && category.isNotEmpty()) {
addShoppingListItemScreenViewModel.setStateValue("Name", name)
addShoppingListItemScreenViewModel.setStateValue("Category", category)
} else {
addShoppingListItemScreenViewModel.setStateValue(
"ShoppingListItem",
shoppingListItem
)
}
}
...
}