android : @AndroidEntryPoint and @HiltViewModel usage
@AndroidEntryPoint is an annotation used in Hilt, which is Google’s recommended library for Dependency Injection (DI) built on top of Dagger.
What does it actually do?
When you mark a class with @AndroidEntryPoint, Hilt generates an individual Hilt component for that specific Android class (in this case, your MainActivity).
Member Injection: It allows the class to receive dependencies from Hilt. Without this, you couldn't use the @Inject annotation to get your ViewModels, Repositories, or API services into the Activity.
Lifecycle Management: It ensures that the dependencies are tied to the Activity's lifecycle. Hilt will automatically handle creating the component in onCreate() and destroying it when the Activity is destroyed.
There are a few things to remember how to use this. We need to use viewModel delegate
@dagger.hilt.android.AndroidEntryPoint
class MainActivity : ComponentActivity() {
private val viewModel: HomeViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
GetMyHomeTheme {
GetMyHomeApp(viewModel = viewModel)
}
}
}
}
How the "Chain" works
When you call by viewModels(), Hilt does the following behind the scenes:
Lookups: It looks at the
HomeViewModelconstructor.Fulfillment: It sees it needs
PropertySearchBackendApiandOkHttpClient.Search: It searches your Hilt Modules (classes marked with
@Module) to find instructions on how to create those specific objects.Delivery: It creates the objects, creates the ViewModel, and hands it to your Activity.
@HiltViewModel // <--- Use this for ViewModels
class HomeViewModel @Inject constructor(
private val propertySearchBackendApi: PropertySearchBackendApi,
private val graphQLClient: OkHttpClient
) : ViewModel() { ... }
Can you have more than one AndroindEntry point - Yes you can
Here is a full example, we will create DetailActivity, then define the DetailScreen and finally DetailViewModel.
@AndroidEntryPoint
class DetailActivity : ComponentActivity() {
private val viewModel: DetailViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
GetMyHomeTheme {
DetailScreen(viewModel = viewModel)
}
}
}
}
And then we will have our DetailScreen here. This is our main layout and it should contains all our UI, at this point it is just a Button that calls viewModel.sayHi().
@Composable
fun DetailScreen(viewModel: DetailViewModel) {
Box(
modifier = Modifier
.fillMaxSize()
.background(BackgroundDark),
contentAlignment = Alignment.Center
) {
Text(
text = "Detail Screen",
color = TextPrimary,
fontSize = 24.sp
)
Button(
onClick = { viewModel.sayHi() }, <---- calling view model function sayHi()
modifier = Modifier
.fillMaxWidth()
.height(56.dp),
colors = ButtonDefaults.buttonColors(
containerColor = PrimaryPurple
),
shape = RoundedCornerShape(12.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
)
{
Text("Detail View", fontSize = 16.sp, fontWeight = FontWeight.Medium)
}
}
}
}
And finally our view model
@HiltViewModel
class DetailViewModel @Inject constructor(
private val propertySearchBackendApi: PropertySearchBackendApi,
private val graphQLClient: OkHttpClient
) : ViewModel() {
fun sayHi()
{
val test = propertySearchBackendApi.toString()
}
}
Comments