viewmodel is being set between screen navigations with composable

38 views Asked by At

I have a small cart system. I want to maintain items added to the cart and for the person they are added for across screens.

But by the time i reach screen2, the viewmodel resets.

@HiltViewModel
class CartVM
    @Inject
    constructor() : ViewModel() {
        private var orderInformation: OrderInformation by mutableStateOf(OrderInformation())
            

  fun submitOrder() { }

  fun getAllCartItems(): List<BasketItem> {
            return orderInformation.cartItems.value
        }

  fun addItemToCart(basketItem: BasketItem) {
            orderInformation.cartItems.value = orderInformation.cartItems.value.plus(basketItem)
            
        }
}

my first screen which adds items to the cart and working well.

@Destination
@Composable
fun ShopScreen(
    vm: CartVM = hiltViewModel(),
    navigator: DestinationsNavigator? = null,
) {
  val item = generateRandomItem();

  Button(onClick= {vm.addItemToCart(item)}){Text(text="add to cart")}

  Button(
                       
                        onClick = {
                             //continue to cart
                            navigator?.navigate(CartScreenDestination)
                        },
                    ) {
                        Text(
                            text = "Go To Cart",
                            modifier =
                            Modifier
                                .fillMaxWidth(),
                            textAlign = TextAlign.Center,
                        )
                    }

}

now when you click continue, it navigates to the following screen but the cart is empty.

@Composable
fun CartScreen(
    vm: CartVM = hiltViewModel(),
    navController: DestinationsNavigator,
) {
  

    val cartItems = vm.getAllCartItems()

}

but cartItems is empty now. How come it doesn't maintain its list. The composables are under one roof with

@HiltAndroidApp
class App : Application() {}

What am i doing wrong? I thought @HiltViewModel makes the view model singleton and as long as i do CartVM: hiltViewModel(), i would get the same instance.

1

There are 1 answers

0
Miroslav Hýbler On BEST ANSWER

@HiltViewModel does not making singletons, it's only help Hilt identify viewModels for injection, so you are making two instances of CartVM. Hilt has Singleton annotation, but it's not applyable for viewModels. You have 2 options on how to solve it.

1. create one instance and share it through the screens

Sorry, i can't make example code because i don't know the navigation you are using.

2. Create singleton repository for holding data

ViewModel instances can share singleton repository where you will keep your data.

@Singleton
class CartRepo @Inject constructor() {
var orderInformation: OrderInformation by mutableStateOf(OrderInformation())
}

And use it like this:

@HiltViewModel
class CartVM @Inject constructor() : ViewModel() {

@Inject
lateinit var cartRepo: CartRepo

    fun getAllCartItems(): List<BasketItem> {
    return cartRepo.orderInformation.cartItems.value
    }

    fun addItemToCart(basketItem: BasketItem) {
    cartRepo.orderInformation.cartItems.value =
        cartRepo.orderInformation.cartItems.value.plus(basketItem)

    }
}