Conflicting `#Inject` - android

a recent hilt update added some warnings and I'm a bit lost on what their trying to tell me and the link in the warning isn't very helpful either.
warning: [Dagger/DuplicateBindings] com.demo.myapp.data.repositories.datastores.AppSettingsRepository is bound multiple times:
#Inject com.demo.myapp.data.repositories.datastores.AppSettingsRepository(com.demo.myapp.data.datastores.CompanySettingsDataStore) [com.demo.myapp.App_HiltComponents.SingletonC]
#Provides #dagger.hilt.android.scopes.ViewModelScoped #org.jetbrains.annotations.NotNull com.demo.myapp.data.repositories.datastores.AppSettingsRepository com.demo.myapp.di.modules.RepositoryModule.provideAppSettingsRepository(com.demo.myapp.data.datastores.CompanySettingsDataStore) [com.demo.myapp.App_HiltComponents.SingletonC ? com.demo.myapp.App_HiltComponents.ActivityRetainedC ? com.demo.myapp.App_HiltComponents.ViewModelC]
This condition was never validated before, and will soon be an error. See https://dagger.dev/conflicting-inject.
I'm hoping someone can better explain the warning, because I don't know what it thinks is duplicated.

The error says that AppSettingsRepository is bound twice: once in SingletonComponent and once in ViewModelComponent.
The SingletonComponent binding comes from an #Inject annotation on AppSettingsRepository. There is something provided in SingletonComponent that depends (directly or indirectly) on AppSettingsRepository, so Dagger automatically puts that binding in SingletonComponent.
The ViewModelComponent binding comes from an explicit #Provides method in RepositoryModule, which is installed in ViewModelComponent.
As mentioned in the linked page, you have three options:
Remove the ViewModelScoped binding. AppSettingsRepository sounds like it should be a singleton anyway, so you can always annotate the class with #Singleton if it's important for all bindings in the same ViewModel to use the same instance.
Move the ViewModelScoped binding to SingletonComponent. The only dependency of your #Provides method is already available in SingletonComponent, so this is certainly possible in this case.
Put a qualifier on the ViewModelScoped binding. This is appropriate if the #Provides method has additional logic beyond simply calling the constructor, and this logic is not wanted in SingletonComponent. In that case, you will want to make anything else in ViewModelComponent that depends on AppSettingsRepository uses a qualifier for this dependency.
Note that SingletonC in the error output is a Dagger component generated by Hilt, corresponding to Hilt's SingletonComponent. The same applies to ViewModelC, which is a Dagger subcomponent corresponding to ViewModelComponent. The warning was generated by Dagger (not Hilt) while trying to process these components.

Related

Why when we init dependency in module we waiting for interface type and not actual object type? - Android

Please someone explain me why when we use dependency injection and initialize the object in the module the provides function return type is interface but in body function we return the actual object. This is example
#Provides
#Singleton
fun providePrefsManager(#ApplicationContext context: Context): PrefsManager {
return PrefsManagerImpl(context)
}
Why here we return PrefsManager instead of PrefsManagerImpl ?
Code to the interface, not the implementation. #Provides methods provide according to their return values, so if you return PrefsManagerImpl, Dagger will only know how to inject PrefsManagerImpl. By returning PrefsManager, Dagger lets you inject PrefsManager directly, so the injecting class doesn't need to be aware of PrefsManagerImpl or any other implementation at all.
More specifically to dependency injection: The concept behind dependency injection is that, for the class you're writing, it's the caller or DI framework that controls which instance or implementation your class receives. This is an "inversion of control" compared to a self-contained class that maintains complete control of which classes or dependencies it uses.
As such, the class you're writing should be as general as possible when specifying its dependencies, which gives you flexibility about which implementations you can supply.
For example: If you need a sort algorithm, it would defeat the flexibility of dependency injection if you always asked specifically for a hypothetical MyBinarySortImpl; instead, you should make your request more general, such as injecting an interface like BinarySorter or Sorter (both also hypothetical). Your caller or dependency injection framework can still supply a MyBinarySortImpl, but by being as general as possible you also free your caller to supply a WellTestedNativeBinarySortImpl or a VeryFastRadixSortImpl. If your implementation needs to be a binary sort, you can specify that, and if it doesn't you can leave it general.
In your specific case, your #Provides method provides a binding of PrefsManager; the implementation happens to be a PrefsManagerImpl. However, the class that consumes PrefsManager is asserting that it doesn't need anything specific to PrefsManagerImpl, it can work when it only uses the interface as described through PrefsManager. That injecting class can now be tested using a FakePrefsManager or a mocking-framework-created mock(PrefsManager), or even a wrapper you could write like LoggingPrefsManager(PrefsManagerImpl(context)). By operating through interfaces rather than implementations, it keeps your options open.

Un-scoped binding in modules vs Constructor injected binding in Dagger

I have an unscoped binding inside the appModule and the same class as constructor injected using the Singleton scope. when I add a declaration inside the appComponent for Foo, the generated code picks up the module binding without any DoubleCheck i.e unscoped binding over the constructor injected Singleton binding why is it so?
#Module
public class AppModule {
#Provides
public Foo provideFoo() {
return new Foo();
}
}
#Component(module = AppModule.class)
#Singleton
public interface AppComponent {
Foo getFoo();
}
#Singleton
class Foo #Inject constructor(){
//..
}
There is some hierarchy in how dependencies are provided, I haven't found documentation on this yet, but I ran into the same thing as well. If I recall it correctly from my testing, the hierarchy of where Dagger tries to get the dependency from is the following:
Bound instances (via component builder methods; i.e. #BindsInstance)
Module provision
Constructor injected classes
Somewhere in this list provisioned dependencies should probably also be included (provisioned from a parent component your component has a dependency on), but I dont know where it would be then in the hierarchy.
Usually there is no need to provide the same dependency in multiple ways, why would you both want to provide the dependency via a Module and via constructor injection? If there are multiple dependencies, but they live in a different scope, try using different scopes instead of just the singleton one.
I can think of one reason where you want to use this mechanic, and thats when you normally want a certain dependency to be provided via either constructor or module injection, but specifically for a test build, you want to overwrite that dependency with a different dependency by changing how the component is composed in a test build (i.e. then changing the DaggerComponent so it requires a #BindsInstance method to overwrite the default dependency with a test dependency).

Dagger 2 - Strategies for reducing number of classes which require annotations

So I am currently in the process of learning dagger 2, and from the tutorials that I've read so far, for a dependency to be injected, the #Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work, or if I don't want other parts of the code to know that dagger exists.
The application structure I have at the moment is:
App Module - where I'd like to put my DI code in (e.g. dagger modules, etc).
Presentation Module - Views/ViewModels etc.
Domain Module - Use Cases etc.
Data Module - Repositories etc.
With pretty much this style of classes contained in my application:
class ExampleViewModelImpl(useCase: ExampleUseCase): ViewModel() in Presentation (gets initialised from an Activity or similar).
class ExampleUseCaseImpl(repository: ExampleRepository): ExampleUseCase in Domain
class ExampleRepositoryImpl(dao: ExampleDao): ExampleRepository in Data
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible? Code examples of how this is achieved would be great.
I am unsure of some terminologies, and wasn't able to find a solution online. If there are good resources which explains what I'm asking, that would also be great.
if I don't want other parts of the code to know that dagger exists.
#Inject is a standard (JSR 330) which Dagger implements. Adding those annotations doesn't have anything to do with Dagger and can be used the same way with other DI frameworks. If it's your code you should just add those #Inject annotations where appropriate. Think of them as documentation: What constructor/field/method must be injected to create & use this object?
The only place where your classes will know that Dagger exists is at the same place where you'd be creating the objects otherwise, too.
Going down that path, of course you could use Dagger without any #Inject annotations, but you'd be writing a lot of unnecessary boilerplate and missing out on the most powerful feature of Dagger at the same time (code generation).
#Inject annotation gets placed inline with fields (for Activities/Fragments) or constructors. However I see that as an issue if I'm not the owner of parts of the code and can't add the required annotations for this technique to work
That's what #BindsInstance with the #Component.Builder is for (add an object to the component) and what #Provides annotated methods are for (create and initialize an object from a module)
If you really want to write code without #Inject, then you'd do exactly this for all of your objects. This means a lot of modules, and even more #Provides annotated methods. It will work, but I don't see the point in writing all those methods if a single #Inject on the constructor has the same effect.
In my opinion the best thing about Dagger is that I can add / remove / change constructor parameters and don't have to touch any other parts of my code since Dagger will generate new code with the new arguments. In your case you'd have to also change the parameters to the #Provides method as well as the constructor invocation.
Next let's look at how to remove #Inject from fields. Basically you don't want to do field injection, so instead of writing an injection method in the component, you'd write provision methods.
#Component
class MyComponent {
fun inject(activity: MyActivity)
}
class MyActivity {
#Inject lateinit var myDep: Dependency
fun onCreate() {
component.inject(this)
}
}
Removing the #Inject we need to use the provision methods instead.
#Component
class MyComponent {
fun provisionMyDependency() : Dependency
}
class MyActivity {
lateinit var myDep: Dependency
fun onCreate() {
myDep = component.provisionMyDependency()
}
}
It will work and everything, but again, you will miss out on the single best feature of Dagger: Code generation. The example above looks alright because I only added a single dependency, but think about what happens to those 2 different implementations when you add / remove / change dependencies, how well it will scale. If you prefer to do things manually any refactoring will become arduous.
With the structure above, what is the minimum number of classes outside of the App Module that I need to touch in order to utilize dagger with as much automated dependency injection as possible?
Your question (especially the title) is in direct conflict with your goal. If you don't want to use those annotations, then you can't use Dagger code generation & injection but have to resort to do it manually as highlighted above.
with as much automated dependency injection as possible
To best utilize Dagger you add #Inject on the constructor and/or fields of every class that should end up on your dependency graph and let Dagger do its thing.

How to use #Qualifers for multiple instances of same type with Dagger 2? [duplicate]

This is a Canonical Question because this is a common error with Dagger 2.
If your question was flagged as a duplicate please read this post carefully and make sure to understand what this error means and why it occured. If this post does not work for you make sure to include where and how you provide the mentioned classes and include the full error message in your question like the one here.
I tried to use a dependency with Dagger 2, but I receive the following error when I try to compile my project:
error: com.example.MyDependency cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.example.MyDependency is provided at
com.example.MyComponent.myDependency()
What does this mean and how can I fix it?
I have a component and tried to provide a dependency. My basic setup looks like this:
// this is the dependency I try to use
class MyDependency {}
#Component
interface MyComponent {
// I want to make it accessible to be used with my component
MyDependency myDependency();
}
tl;dr You forgot to either add an #Inject to your constructor so that Dagger can use Constructor Injection to provide the object, or you need some method in one of your Modules that creates or binds the object.
What's going on?
Have a good look at the error message: It states that you try to request a dependency but Dagger has no way to provide or create it. It simply does not know how to, because it cannot be provided without an #Inject constructor or from an #Provides-annotated method.
A close look at the error message shows the class (a) that you are trying to provide and the component (b) that needs it.
com.example.MyDependency (a) is provided at
com.example.MyComponent.myDependency() (b)
You have to make sure that (b) can create or provide (a) to fix your issue.
It looks a bit more complex if you tried to inject your dependency somewhere else, but you can still see the full stack of events—in this case a constructor injection missing a dependency. The class (a) that you are trying to provide and the location (b) where Dagger tried injecting it. It also tells you where that dependent class was created (c) and again the component (d) that failed providing (a).
com.example.MyDependency cannot be provided without an #Inject constructor or from an #Provides-annotated method.
com.example.MyDependency (a) is injected at
com.example.DependentClass.(dependency) (b)
com.example.DependentClass is provided at (c)
com.example.MyComponent.myDependency() (d)
The same applies here: Make sure that (d) knows how to provide (a) and you're good to go.
How do I fix this?
Have a look at the error as shown above. Make sure you understand where it occured and what you are trying to inject. Then tell Dagger how to provide your object.
an #Inject constructor
As the error states, you try to use MyDependency but MyComponent does not know how to do that. If we have a look at the example it becomes clear why:
class MyDependency {}
The class has no #Inject annotated constructor! And there is no other module in the component, so there is nothing Dagger could do.
If you want to use constructor injection you can just add an #Inject annotated constructor and are done. Dagger will see this constructor and know how to create your class.
class MyDependency {
#Inject
MyDependency() { /**/ }
}
That is all you have to do when you can make use of constructor injection.
from an #Provides-annotated method
The error message states a second option, which allows you to provide an object if you don't want—or can't—use constructor injection. You can also add a #Provides annotated method to a module and add this module to your component.
#Module
class MyModule {
#Provides
MyDependency provideMyDependency() {
return new MyDependency();
}
}
#Component(modules = MyModule.class)
interface MyComponent {
MyDependency myDependency();
}
This way Dagger can use your module to create and provide your dependency. It is a little bit more boilerplate than using Constructor Injection, but you will have to use Modules for everything that needs further setup or that does not have an annotated constructor, e.g. third party libraries like Retrofit, OkHttp, or Gson.
There are also other ways to provide a dependency from a component. A #SubComponent has access to its parents dependencies, and a component dependency can expose some of its dependencies to its dependent components. But at some point everything Dagger provides needs to either have an #Inject constructor or a Module providing it.
But I did add MyDependency!
Pay close attention to the details. You probably are using an interface when you are only providing the implementation, or try to use a parent class when Dagger only knows about the subclass.
Maybe you added a custom #Qualifier or used #Named("typeA") with it. To Dagger this is a completely different object! Double check that you actually provide and request the same dependency.
Read the error and make sure that you either have an #Inject annotated constructor, a module that has a #Provides method that provides that type, or a parent component that does.
What if I want to provide an implementation for my interface?
A simple example like the following shows how one class extends another:
class MyDependency extends MyBaseDependency {
#Inject MyDependency() { super(); }
}
This will inform Dagger about MyDependency, but not about MyBaseDependency.
If you have one class implementing an interface or extending a super class you have to declare that. If you provide MyDependency this does not mean that Dagger can provide MyBaseDependency. You can use #Binds to tell Dagger about your implementation and provide it when the super class is required.
#Module
interface MyModule {
#Binds
MyBaseDependency provideMyBaseDependency(MyDependency implementation);
}

What is the purpose of adding scope modifiers to #Components in Dagger2?

Say I have a class (or a #Provides method) annotated with #Singleton. This makes sense to me, whenever a dependency is provided from this class, the same instance will always be returned.
What I am trying to understand is why there is then a requirement for components that use that module to also be marked as #Singleton. The purpose of adding a scope to a component does not make sense to me. A component is an interface, that dagger uses to implement the actual injection.
If I try to compile my app with my dependency class marked as #Singleton, but do not have #Singleton marked on a component that injects this dependency, I get an error.
com.example.whatever.MyComponent (unscoped) cannot depend on scoped components
Adding #Singleton to the component makes this error go away, but I want to understand why. Can anyone help me understand this? Thanks!
Adding #Singleton on your component allows you to use #Singleton on your provider methods in your module you specify for your component. Scoped providers make it so that you can have only one instance from that given module without any additional magic beyond what Dagger2 generates for you.
#Singleton
#Component(module={BlahModule.class})
public interface SingletonComponent {
Blah blah();
}
#Module
public class BlahModule {
#Provides
#Singleton
public Blah blah() {
return new BlahImpl();
}
}
According to the Dagger 2 design doc, it is meant to make intention clear ("a declaration of intention") and to allow for better compile-time checking.
That declaration enables dagger to enforce the following constraints:
A given component may only have bindings (including scope annotations
on classes) that are unscoped or of the declared scope. I.e. a
component cannot represent two scopes. When no scope is listed,
bindings may only be unscoped.
A scoped component may only have one
scoped dependency. This is the mechanism that enforces that two
components don’t each declare their own scoped binding. E.g. Two
Singleton components that each have their own #Singleton Cache would
be broken.
The scope for a component must not appear in any of its
transitive dependencies. E.g.: SessionScoped -> RequestScoped ->
SessionScoped doesn’t make any sense and is a bug.
Singleton is
treated specially in that it cannot have any scoped dependencies.
Everyone expects Singleton to be the “root”.
This also makes some sense given the implementation of Dagger 2: Because Scopes are implemented via memoization and the user is responsible for instantiating a new Component instance for every new scope, then it makes sense that the Component has a lifetime (and set of provisions) to which the scope also applies.

Categories

Resources