Why some people uses #Inject for constructor of classes and some other did not use this annotation for constructor.
Is it optional to use this?
It's not needed if you provide instance yourself:
//without #Inject
class SomeInstance contructor(...): SomeInstanceInterface{}
#Module
class Module{
#Provides()
fun provide():SomeInstanceInterface {
return SomeInstance(...)
}
}
But if you want that Dagger create instance for you, then you need to mark constructor with #Inject and ask Dagger to create instances:
#Module
class Module{
#Provides()
fun provide(inst: SomeInstance):SomeInstanceInterface = inst
}
or
#Component
interface Component{
fun someInstance():SomeInstanceInterface
}
Related
I have an android application and I would like to perform dependency injection on a class which is not activity or fragment therefore the applicationContext is not present.
#HiltAndroidApp
class App: Application {
#Inject
lateinit var analytics: Analytics
override fun onCreate() {
super.onCreate()
// other details
}
}
My AppModule
#Module
#InstallIn(ApplicationComponent::class)
abstract class AppModule() {
companion object {
#Provide
#Singleton
fun provideSomeClass(): SomeClass = SomeClass()
}
}
If I try to inject SomeClass in a activity it works fine but not on a non activity class it fails with an error Object is not initialized.
class Consumer {
#lateinit var SomeClass someClass;
}
Can someone point what I am doing wrong?
Inject a field of a non-Activity class
To do this you have to create an Interface that will be an #EntryPoint,
and pass to that interface the ApplicationContext.
Code sample:
// No annotations here
class Consumer(ctx: Context) { // pass here the Android context
// Create an Interface (required by #InstallIn)
#EntryPoint
#InstallIn(SingletonComponent::class) // this could be implementation specific
interface Injector {
fun getSomeClass(): SomeClass // getter that will be injected
// you can also define a proper Kotlin Getter here
}
// create the injector object
val injector = EntryPoints.get(ctx, Injector::class.java)
// retrieve the injected object
val someObject = injector.getSomeClass()
suspend fun andFinallyUseIt() {
someObject.someMethod()
}
}
More:
Make sure you don't winde your scope
Read more: Dagger #EntryPoint
Use inject in constructor
class Consumer #Inject constructor(private val someclass:SomeClass){
//some code
}
With the new dependency injection library Hilt, how to inject some classes into ViewModel without constructor params and ViewModelFactory?
Is it possible?
Like in Fragment, we use only #AndroidEntryPoint and #Inject.
how to inject some classes into ViewModel without constructor params and ViewModelFactory? Is it possible?
Hilt supports constructor injection of ViewModel via the #HiltViewModel (previously #ViewModelInject) annotation.
This allows for any #AndroidEntryPoint-annotated class to redefine their defaultViewModelProviderFactory to be the HiltViewModelFactory, which allows the creation of #HiltViewModel-annotated ViewModels correctly instantiated via Dagger/Hilt.
NEW HILT VERSION:
#HiltViewModel
class RegistrationViewModel #Inject constructor(
private val someDependency: SomeDependency,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
...
}
OLD HILT VERSION:
class RegistrationViewModel #ViewModelInject constructor(
private val someDependency: SomeDependency,
#Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
...
}
And then
#AndroidEntryPoint
class ProfileFragment: Fragment(R.layout.profile_fragment) {
private val viewModel by viewModels<RegistrationViewModel>() // <-- uses defaultViewModelProviderFactory
Yes, it is possible to inject dependency into a ViewModel class without constructor params. First we need to create a new interface annotated with #EntryPoint to access it.
An entry point is an interface with an accessor method for each
binding type we want (including its qualifier). Also, the interface
must be annotated with #InstallIn to specify the component in which to
install the entry point.
The best practice is adding the new entry point interface inside the class that uses it.
public class HomeViewModel extends ViewModel {
LiveData<List<MyEntity>> myListLiveData;
#ViewModelInject
public HomeViewModel(#ApplicationContext Context context) {
myListLiveData = getMyDao(context).getAllPosts();
}
public LiveData<List<MyEntity>> getAllEntities() {
return myListLiveData;
}
#InstallIn(ApplicationComponent.class)
#EntryPoint
interface MyDaoEntryPoint {
MyDao myDao();
}
private MyDao getMyDao(Context appConext) {
MyDaoEntryPoint hiltEntryPoint = EntryPointAccessors.fromApplication(
appConext,
MyDaoEntryPoint.class
);
return hiltEntryPoint.myDao();
}
}
In the code above we created a method named getMyDao and used EntryPointAccessors to retrieve MyDao from Application container.
Notice that the interface is annotated with the #EntryPoint and it's
installed in the ApplicationComponent since we want the dependency
from an instance of the Application container.
#Module
#InstallIn(ApplicationComponent.class)
public class DatabaseModule {
#Provides
public static MyDao provideMyDao(MyDatabase db) {
return db.MyDao();
}
}
Though the code above has been tested and worked properly but it is not the recommended way to inject dependency into ViewModel by android officials; and unless we know what we're doing, the best way is to inject dependency into ViewModel through constructor injection.
I am developing an Android project with Kotlin and Dagger 2. I have a MyModule in which I defined some provider functions.
#Module
object MyModule {
#Provides
#JvmStatic
internal fun provideSomething(): Something {
...
}
}
In my Foo class, I inject Something as a member variable:
class Foo(#Inject val something: Something) {
}
But now I want to have this Foo class also be injectable to another class, e.g. in a class called Bar:
class Bar(#Inject val foo: Foo)
How to make that happen? If in Java I could do:
class Foo {
// I inject something
#Inject
private Something something;
// I also make Foo to be injectable to other class
#Inject
public Foo()
}
But how to achieve the same in my Kotlin Foo class?
Assuming Something is a class created by you. You don't even need a #Module to provide it.
You can do this,
class Something #Inject constructor() {
}
You just add #Inject to Something constructor and that's it, Dagger knows how to provide it. And then in your Foo class
class Foo #Inject constructor() {
#Inject
lateinit var something: Something
}
Done, no need to have #Module and #Component if you own Something class.
But
If the class Something is not under your control then we need to take the long route such as,
Step 1: Create Module
#Module
object MyModule {
#Provides
#JvmStatic
internal fun provideSomething(): Something {
...
}
}
Step 2: Define Component
#Component(modules = [MyModule::class])
interface MyComponent {
fun inject(foo: Foo) //mention the place where you need to inject variables
}
Step 3: Start Component
class Foo #Inject constructor(){
#Inject
lateinit var something:Something
init{
DaggerMyComponent().create().inject(this) //do this before using `something` or else face `UninitializedPropertyException`
//You can now freely use `something`, **Dagger** has already performed his magic
}
}
Update:
Let's say Something has a parameterized constructor and looks like this,
class Something #Inject constructor(mRandom : RandomClass), again two possibilities arise
If RandomClass is owned by you, you can just add #Inject to this RandomClass constructor like this,
class RandomClass #Inject constructor(){
}
that's it, Dagger will provide RandomClass wherever needed.
And If RandomClass is not under your control you need to provide it using a #Module like this,
#Module
object RandomModule {
#JvmStatic
#Provides
fun providesRandomClass(): RandomClass {
...
}
}
Add this #Module to your #Component and start the #Component wherever dependencies are needed(Example is already provided above in steps).
Moral of the story is, One way or another Dagger should know how to provide RandomClass
For your specific example, let's say we have
class Something #Inject constructor(mString:String,customType:CustomType){
}
Just tell Dagger how to provide that String and CustomType
#Module
object CustomModule {
#JvmStatic
#Provides
#Named("AnyName") //Just to differentiate which string we need
fun providesString() = "AnyName"
#JvmStatic
#Provides
fun providesCustomType(): CustomType {
...
}
}
and then this last little modification over Something constructor,
class Something #Inject constructor( #Named("AnyName") mString:String, customType:CustomType ){
}
In kotlin you have to do it like this:
class Foo #Inject constructor(val something: Something) {
}
I'm not so sure if you can name them the same either.
any possible way to use provide this using bind annotation?
#Singleton
#Provides
fun provideUtils(context: Context): Utils {
return Utils(context)
}
If your Utils class has an #Inject constructor, e.g.
class Utils #Inject constructor(private val context: Context) {
// ...
}
... then you can bind it like so, and Dagger should be able to figure out how to create it (given that you're providing a Context somewhere):
#Singleton
#Binds
fun bindUtils(utils: Utils): Utils
You should use constructor injection here. You don't need #Provides or #Binds if you use constructor injection.
#Singleton // scope on the class
class Utils #Inject constructor(private val context: Context)
That's all.
I understand that the constructor injection can be used to avoid the declartion of module for downstream injections.
For example, by adding the scope and inject annotation , I don't need to write the module to provide the instance.
#Singleton
public class Injection {
#Inject
Injection ( Dependency dependency ) {...}
}
so I can get instance by using following annotation in other class
#inject
Injection myInjection;
However, is it possible that I can get the same result if I want it be injected from interface declare?
such as :
#Singleton
public class Injection implement InjectionInterface {
#Inject
Injection (Dependency dependency) {...}
}
#inject
InjectionInterface myInjection; // will I get the instance of Injection?
No, you need to create a module for that
#Module
public class MyModule {
InjectionInterface injectionInterface(Injection injection) {
return injection;
}
}
You can also use #Binds which does exactly the same thing.
#Module
public abstract class MyModule {
#Binds
abstract InjectionInterface injectionInterface(Injection injection);
}