@HiltViewModel

@HiltViewModel and Injecting into Composables

A ViewModel joins the graph with @HiltViewModel and an @Inject constructor. The factory from ViewModel disappears, and the constructor asks for the interface rather than a concrete class:

ui/ViewModels.kt: both ViewModels are now built by Hilt (excerpt)Kotlin
@HiltViewModel
class CatalogViewModel @Inject constructor(
  private val repo: BookRepository,              // an interface: Hilt picks the binding
) : ViewModel() {
  ...
@HiltViewModel
class CartViewModel @Inject constructor(
  private val saved: SavedStateHandle,          // Hilt supplies it for every ViewModel
) : ViewModel() {

The hosting activity is marked @AndroidEntryPoint, which also allows field injection into the activity (@Inject lateinit var repo: BookRepository). In composables, hiltViewModel() from androidx.hilt:hilt-lifecycle-viewmodel-compose 1.4.0 replaces viewModel(factory = ...), so CatalogRoute's parameter is now vm: CatalogViewModel = hiltViewModel(). Scoping is as in ViewModel and UDF: per back-stack entry inside a NavHost destination, per activity at the top of setContent.

Hilt cannot inject composables, which are functions; pass what a screen needs from its route. Values known only at run time, such as a book id, arrive through SavedStateHandle (saved.toRoute<BookDetail>()) or assisted injection (@AssistedInject), and a class Hilt cannot reach, such as a ContentProvider, uses an @EntryPoint interface.