Dagger2 + ViewModel + Repository - android

I am new to Dagger 2 and trying to implement it in Kotlin. Here i am trying to inject my repository object into viewmodel. I am successfully able to inject it this way
public class LoginViewModel #Inject constructor(var mApplication: Application, var repository: LoginRepository) :
ViewModel() {
This is how my repository looks like
class LoginRepository #Inject constructor(val retrofit: APICallInterface) {
This is how my module looks like
#Module
class BaseModule {
#Provides
fun getRetrofit(): APICallInterface {
return Retrofit.Builder()
.baseUrl("https://samples.openweathermap.org/data/2.5/")
.addConverterFactory(GsonConverterFactory.create())
.build().create(APICallInterface::class.java)
}
What i am unable to understand is how Dagger 2 is able to provide an object for repository as i have not mentioned it in any module with #Provides annotation.
I have tried following many blogs and few stckoverflow questions available here but none of them is solving my doubt.
Any help/explanation will be appreciated.

What i am unable to understand is how Dagger 2 is able to provide an object for repository as i have not mentioned it in any module with #Provides annotation.
You're using constructor injection by annotating the constructor with #Inject:
[#Inject] Identifies injectable constructors, methods, and fields.
So, by adding the annotation, Dagger becomes aware of the constructor and knows how to create the object when needed.
class LoginRepository #Inject constructor(..)
If your constructor wouldn't have the annotation on it then you'd need a #Provides annotated method in a module so that Dagger can access the dependency, but you should use #Provides annotated methods primarily for objects that need additional setup and/or initialization.

Related

Kotlin Dagger - Inject Fragment values into viewmodel

I need a solution where i could inject Fragment arguments/extras (one Longand one String to be specific) into Fragment's viewmodel and based on these values viewmodel could run it's setup in init {..}
All the ViewModel's injections are fine, dependencies in ViewModel's #Inject construct([dependencies]){..} are provided and working correctly.
My SubComponent looks like this at the moment :
`
#Scope
annotation class MyFragmentScope
#MyFragmentScope
#Subcomponent(modules = [MyFragmentModule::class])
interface MyFragmentSubcomponent : Injector<MyFragment> {
#Subcomponent.Builder
interface Builder : Injector.Factory<MyFragment>
}
#Module
abstract class MyFragmentModule {
#Binds
#IntoMap
#MyFragmentScope
#ViewModelKey(MyFragmentViewModel::class)
abstract fun bindMyFragmentViewModel(
viewModel: MyFragmentViewModel
): ViewModel
}
`
I would be super thankful for any support
Cheers
I tried to create a new ViewModelFactory with additional parameter, but sadly that didn't work out
Tried to use Hilt or Assisted Injection, which also didn't work out since my project is strictly restricted to Dagger v 2.16, if i try to update - tons of bugs arise from this old codebase, it would take months rewriting everything.
Maybe i just did something wrong

Dagger hilt: Difference between annotating a class #Singleton and a provides function #Singleton

My question is pretty simple and straightforward: What is the difference between the two annotations / examples:
Example one
#Singleton
class MySingletonClass() {}
#Module
#InstallIn(FragmentComponent::class)
abstract class MyFragmentModule {
#Provides
fun provideMySingletonClass() = MySingletonClass()
}
Eaxmple two
class MySingletonClass() {}
#Module
#InstallIn(FragmentComponent::class)
abstract class MyFragmentModule {
#Singleton
#Provides
fun provideMySingletonClass() = MySingletonClass()
}
The only difference I know is, that the second example gives me the following error:
error: [Dagger/IncompatiblyScopedBindings] FragmentC scoped with #dagger.hilt.android.scopes.FragmentScoped may not reference bindings with different scopes:
Does that mean, that the #Singleton annotation in example one is simply ignored?
In Example One, your #Singleton annotation is ignored, but only because you are calling the constructor yourself in your #Provides method. Because Dagger doesn't interact with your MySingletonClass constructor, it cannot read or use the annotation.
If your #Singleton class MySingletonClass had an #Inject constructor—even an empty one—then Dagger would be able to interact with it directly as long as you also delete the #Provides fun that would override the constructor detection. Once you've done that, the behavior of #Singleton would be the same in either syntax.
Regarding the error message "error: [Dagger/IncompatiblyScopedBindings] XXX scoped with #YYY may not reference bindings with different scopes": #Andrew The real problem here is that in Example Two you're trying to declare a #Singleton binding in a Module that you install in your FragmentComponent. #Singleton bindings can only happen in a #Singleton component, which in Hilt is SingletonComponent. I don't remember for sure, but I think your Example One (with the edits I described) would work with singleton behavior and without an error, because Dagger would automatically select the appropriate component in the hierarchy to install your MySingletonClass.

whats the difference between #Provide and #Inject in dagger2?

Whats the difference between #Inject and #Provide ?
although both are used for providing dependencies then whats the difference ?
This is covered very well in documentation, #Inject and #Provides are two different ways of introducing dependencies in the dependency graph. they are suited for different use cases
#Inject
Easy to use, simply add #Inject on constructor or property and you are done
It can be used to inject types as well as type properties
In a subjective way it may seem clearer than #Provides to some people
#Provides
If you don't have access to source code of the type that you want to inject then you can't mark its constructor with #Inject
In some situations you may want to configure an object before you introduce it in dependency graph, this is not an option with #Inject
Sometimes you want to introduce an Interface as a dependency, for this you can create a method annotated with #Provides which returns Inteface type
Following are the examples of above three points for #Provides
If you can't access source code of a type
// You can't mark constructor of String with #Inject but you can use #Provides
#Provides
fun provideString(): String {
return "Hello World"
}
Configure an object before introducing in the dependency graph
#Provides
fun provideCar(): Car {
val car = Car()
// Do some configuration before introducing it in graph, you can't do this with #Inject
car.setMaxSpeed(100)
car.fillFuel()
return car
}
Inject interface types in dependency graph
interface Logger { fun log() }
class DiscLogger : Logger{ override fun log() { } }
class MemoryLogger : Logger { override fun log() { } }
#Provides
fun provideLogger(): Logger {
val logger = DiscLogger() \\ or MemoryLogger()
return logger
}
#Inject:- It is used to inject dependencies in class.
#provides:- Required to annotated the method with #provide where actual instance is created.
This has covered in Dagger-2 documentation clearly.
What #Inject can Do:
Use #Inject to annotate the constructor that Dagger should use to
create instances of a class. When a new instance is requested, Dagger
will obtain the required parameters values and invoke this
constructor.
If your class has #Inject-annotated fields but no #Inject-annotated
constructor, Dagger will inject those fields if requested, but will
not create new instances. Add a no-argument constructor with the
#Inject annotation to indicate that Dagger may create instances as
well.
Similarly dagger can create for methods also.
Classes that lack #Inject annotations cannot be constructed by
Dagger.
What #Inject can't Do: and can be used #Provides annotation
Interfaces can’t be constructed.
Third-party classes can’t be annotated.
Configurable objects must be configured!

Problems with Hilt DI

Sorry for seally question, I have never used Dagger/Hilt before. Can't understand how to inject dependencies in my app. Here is what have now:
#InstallIn(Application::class)
#Module
abstract class RepositoryModule {
#Binds
abstract fun bindProductRepository(productRepository: ProductRepository): IProductRepository
#Binds
abstract fun bindCategoryStorage(categoryStorage: CategoryStorageImpl) : CategoryStorage
companion object {
#Provides
#Singleton
fun createRoomDataBase(#ApplicationContext context: Context) : ProductRoomDatabase = ProductRoomDatabase.getDatabase(context)
#Provides
#Singleton
fun createProductDao(productRoomDatabase: ProductRoomDatabase) = productRoomDatabase.productDao()
#Provides
#Singleton
fun createCategoryDao(productRoomDatabase: ProductRoomDatabase) = productRoomDatabase.categoryDao()
}
}
Hilt comes with three pre-made components:
ApplicationComponent | SingletonComponent - component that contains application-level dependencies and live until application lives.
ActivityComponent - component that contains Activity-level dependencies
FragmentComponent - component that contains Fragment level dependencies
InstallIn annotation suggests that all dependendencies in the current module will be available in the argument of the annotation.
There are many courses and tutorials about this topic, but most of them just rephrase the original documentation. I would strongly suggest you read this documentation, from official Android website
https://developer.android.com/training/dependency-injection/hilt-android

Provide all childs of a class with dagger

im creating a highly modular application, i have a lot of clases that need to be injected, all of them are childs (not direct childs) of the same class, none of them have constructor parameters.
I want to avoid having to create a "#Provides" method for each one of them in my module.
Is there a way to tell dagger to automatically provide all the classes that implement a base interface? Or is it possible to do it myself using reflection?
Im using dagger-android with kotlin
Update: Ill post some code to illustrate
In one of the modules i have this interface
interface ExampleClass: BaseExample {
fun doSomething()
}
}
Then in the main app i implement it
class ExampleClassImpl #Inject constructor() : ExampleClass {
override fun doSomething(){
}
}
The class where i need it is a Viewmodel created with dagger so inject works on the constructor.
class ExampleViewModel #Inject constructor(val exmpl :ExampleClass) : BaseViewModel {
}
I want to inject that ExampleClassImpl, to do that i need to create a #module with a method annotated with #Provides or #Bind and return that class.
Without the provider i get an error at compile time:
error: [Dagger/MissingBinding] com.myapp.ExampleClassImpl cannot be provided without an #Provides-annotated method.
You want to inject ExampleClass, but Dagger only knows about ExampleClassImpl. How would Dagger know that you want that specific subclass?
Moreover, you say you have many subclasses that you want to inject. How would Dagger know which one to provide to a constructor expecting the base class?
If you want ExampleViewModel to get an instance of ExampleClassImpl then you can simply change the declaration to:
class ExampleViewModel #Inject constructor(val exmpl :ExampleClassImpl)
Doing so you lose the ability to swap the constructor argument with a different implementation of ExampleClass.
The alternative is to have one #Named #Provides method per subclass. So something like:
// In your module
#Provides
#Named("impl1")
fun provideExampleClassImpl1(impl: ExampleClassImpl): ExampleClass = impl
// When using the named dependency
class ExampleViewModel #Inject constructor(#Named("impl1") val exmpl :ExampleClass)

Categories

Resources