Pablo
11/22/2024, 9:23 AM@Inject lateinit var
from official android Hilt
documentation: https://developer.android.com/training/dependency-injection/hilt-android?hl=es-419
I'm doing the same they show in their lateinit var sample:
class MyModelViewModel() : ViewModel() {
@Inject lateinit var myModelRepository: MyModelRepository
But that gives me this exception:
kotlin.UninitializedPropertyAccessException: lateinit property myModelRepository has not been initialized
If I try adding @HiltViewModel
on class MyModelViewModel()
then I got this error:
error: [Hilt] @HiltViewModel annotated class should contain exactly one @Inject or @AssistedInject annotated constructor.
ephemient
11/22/2024, 10:03 AMAndrei Mandychev
11/22/2024, 10:04 AM@HiltViewModel
and then you can pass your repository via parameter in constructor. Note, that MyModelRepository has to be provided: either using a provider method or constructor injection.
@HiltViewModel
class MyModelViewModel(
private val myModelRepository: MyModelRepository
) : ViewModel()
for MyModelRepository
option1, smth like this
@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {
@Provides
fun provideMyDependency(): MyModelRepository {
return MyModelRepository()
}
}
options2:
class MyModelRepository @Inject constructor() {...}
Pablo
11/22/2024, 10:12 AMPablo
11/22/2024, 10:13 AM@Inject lateinit var
from official android Hilt
documentation: https://developer.android.com/training/dependency-injection/hilt-android?hl=es-419Pablo
11/22/2024, 10:13 AMPablo
11/22/2024, 10:14 AMPablo
11/22/2024, 10:15 AMephemient
11/22/2024, 10:15 AMPablo
11/22/2024, 10:17 AMephemient
11/22/2024, 10:19 AM@Inject lateinit var
doesn't magically populate itself. so you may not call the constructor yourself. (that's the whole thing with dependency injection)Pablo
11/22/2024, 10:20 AMephemient
11/22/2024, 10:20 AM@Inject constructor
which you don't call, you get the object injected to you.Pablo
11/22/2024, 10:21 AMPablo
11/22/2024, 10:22 AMephemient
11/22/2024, 10:27 AM@HiltViewModel
public class MyViewModel @Inject constructor() extends ViewModel {
@Inject
lateinit var dependency: Dependency
}
val viewModel = MyViewModel() // Dagger is not involved at all, dependency is still unset
val viewModel: MyViewModel by viewModels() // Dagger constructs and injects
Pablo
11/22/2024, 10:38 AMephemient
11/22/2024, 10:51 AM@HiltViewModel
public class MyViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
) extends ViewModel {
val id: Int = savedStateHandle["id"]
}
val viewModel: MyViewModel by viewModels(
extrasProducer = {
MutableCreationExtras(defaultViewModelCreationExtras).apply {
set(DEFAULT_ARGS_KEY, bundleOf("id" to id))
}
},
)
but it's really more work than just using assisted injectPablo
11/22/2024, 11:02 AMPablo
11/22/2024, 11:02 AMPablo
11/22/2024, 11:02 AMephemient
11/22/2024, 11:02 AMephemient
11/22/2024, 11:02 AMPablo
11/22/2024, 11:03 AMPablo
11/22/2024, 11:03 AMephemient
11/22/2024, 11:05 AMPablo
11/22/2024, 11:09 AMPablo
11/22/2024, 11:09 AMephemient
11/22/2024, 11:30 AMPablo
11/22/2024, 11:34 AMephemient
11/22/2024, 11:35 AMephemient
11/22/2024, 11:36 AMPablo
11/22/2024, 11:37 AM@AndroidEntryPoint
class CustomClass @Inject constructor (val repository: Repository, val name: String) {
Let's say I only want to inject the repository parameter, but I want to pass the name parameter during initialization like so:
val customClass = CustomClass("name")
with @Inject constructor
I'm forced to add a lot of boirlerplate and complexity:
@AndroidEntryPoint
class CustomClass @AssisgtedInject constructor (
val repository: Repository,
@Assisted val name: String
) {
@AssistedFactory
interface CustomClassFactory {
fun create(name: String): CustomClass
}
}
To add more boilerplate and useless complexity, that forces you to create the CustomClass
class with the interface
instead of the normal class
, and calling the create
method.
On the other hand, if you instead do it using @Inject lateinit var
, is that simple:
@AndroidEntryPoint
class CustomClass(val name: String) {
@Inject lateinit var repository: Repository
}
Now, think that this is a super simple example with just one non Hilt parameter, but this can get a lot more big as you know.Pablo
11/22/2024, 11:38 AMephemient
11/22/2024, 11:40 AMCustomClass(...)
directly for reasons specified previously. so it is handled by a factory method instead, and that needs to be in an interface so that Dagger can implement it. there's nothing limiting you from putting multiple factory methods into the same interface though, if you wanted to amortize thatHuixing.Wang
11/23/2024, 8:59 AMPablo
11/23/2024, 9:35 AMHuixing.Wang
11/23/2024, 9:37 AMPablo
11/23/2024, 11:51 AMPablo
11/23/2024, 11:52 AMclass CustomClass(val repository: Repository, val name: String) {
Let's say I only want to inject the repository parameter, but I want to pass the name parameter during initialization like so:
val customClass = CustomClass("name")
how will achieve it with koin?ephemient
11/23/2024, 11:56 AM