0

I have this structure in my MainActivity:

val navController = rememberNavController()
NavHost(
    navController = navController,
    startDestination = ItemsScreen.route
) {
    composable(
        route = ItemsScreen.route
    ) {
        ItemsScreen(
            navController = navController
        )
    }
    composable(
        route = ItemDetailsScreen.route + "/{itemId}",
        arguments = mutableStateListOf(
            navArgument("itemId") {
                type = NavType.StringType
            }
        )
    ) { backStackEntry ->
        val itemId = backStackEntry.arguments?.getString("itemId") ?: ""
        ItemDetailsScreen(
            navController = navController,
            itemId = itemId
        )
    }
}

In the ItemDetailsScreen a LazyColumn:

LazyColumn {
    items(
        items = itemsResponse.data
    ) { item ->
        ItemCard(
            item = item,
            onItemClick = {
                navController.navigate(ItemDetailsScreen.route + "/${item.id}")
            }
        )
    }
}

And on item click I navigate to the ItemDetailsScreen:

fun ItemDetailsScreen(
    navController: NavController,
    itemId: String,
    viewModel: ItemDetailsViewModel = hiltViewModel()
) {
    Log.d(TAG, itemId)
}

As seen, the ViewModel object is created in the constructor. When I open the ItemDetailsScreen the log statement is triggered twice. If I comment this line:

//viewModel: ItemDetailsViewModel = hiltViewModel()

The log statement works as expected, it prints the itemId only once. How to use the ViewModel object so it can trigger the log statement only once?

Here is also the ViewModel class:

@HiltViewModel
class ItemDetailsViewModel @Inject constructor(
    private val useCases: UseCases
): ViewModel() {
    private val _itemState = mutableStateOf<Response<Item>>(Success(Item()))
    val itemState: State<Response<Item>> = _itemState

    fun getItem(id: String) {
        viewModelScope.launch {
            useCases.getItem(id).collect { response ->
                _itemState.value = response
            }
        }
    }
}

1 Answer 1

2

You need not worry about the log statement being printed twice. There's nothing wrong with the viewModel creation code. The log statment is printed twice because it is directly inside a composable function and composables recompose a lot (sometimes even in an unpredictable way). If you want to do some operation only when the composable is composed the first time, put it inside a LaunchedEffect block. Check out the documentation to learn more about these effect handlers.

Sign up to request clarification or add additional context in comments.

1 Comment

It worked using LaunchedEffect. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.