dagger2 is throwing an error: cannot be provided without an @Provides-annotated method. in my android project's build
As suggested in this answer, just add your App class in the android manifest under the application tag.
<application ...
android:name = ".App" ...>
...
How do I fix Dagger 2 error '... cannot be provided [...]'?
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);
}
Dagger 2 error: dependency “cannot be provided without an @Provides-annotated method
Seems like I've figured out what was wrong
the problem. the DeliveriesModule which is a module of DeliveriesActivity so i have to make another Module for DeliveriesListFragment and provide the DeliveryListUseCase
Thank you, @Blackbelt, for giving me a hint
Dagger 2 error: dependency cannot be provided without an @Inject constructor while it actually annotated with @Inject
Seems like I've figured out what was wrong with my Dagger 2 setup. It's not possible to use the same scope in both component and subcomponents. It's required to define a new scope for subcomponent. In my case I've ended up creating @Screen scope for me subcomponent.
I'd say that this is a small but very annoying defect in Dagger 2. Apparently dagger-compiler reports nice and understandable error about the same scopes in a parent component and child component if child component is extended with a parent component as dependency. But completely misleading error is reported by the compiler if parent component and child subcomponent share the same scope.
Thank you, @lukas, for giving me a hint here https://stackoverflow.com/a/30383088/808313 that led to a problem resolution.
Dagger2 Can't provide dependency of activity to dagger
dagger.android does do this automatically: See the explicit version of the binding that @ContributesAndroidInjector
generates for you, where the generated AndroidInjector.Factory
contains a @BindsInstance
binding of the type you request here.
This isn't working for you because you are injecting MainActivity in a binding that is installed on your top-level component. This is a problem because AppComponent will exist before the Activity does, and will also be replaced as Android recreates the Activity: Passing an instance through @Component.Builder
is not a way around this problem.
Instead, move your FactoryVmModule::class
to within the subcomponent that @ContributesAndroidInjector
generates, which you can do by including it in the modules
attribute on @ContributesAndroidInjector
. Dagger will create a different subcomponent instance per Activity instance, so your FactoryVmModule will always have a fresh binding to MainActivity.
@Module
abstract class MainActivityModule {
@ContributesAndroidInjector(
modules = [ViewModelModule::class, FactoryVmModule::class]
)
abstract fun injectMainActivity(): MainActivity
}
I moved your ViewModelModule class there as well; though it's possible you could leave it in your top-level Component if it doesn't depend on anything belonging to the Activity, you might want to keep them together. Bindings in subcomponents inherit from the application, so you can inject AppComponent-level bindings from within your Activity's subcomponent, but not the other way around. This means you won't be able to inject VM instances (here, TestVM) outside your Activity, but if they depend on the Activity, you wouldn't want to anyway: Those instances might go stale and keep the garbage collector from reclaiming your finished Activity instances.
Related Topics
When to Use: Java 8+ Interface Default Method, Vs. Abstract Method
Wait For Page Load in Selenium
What's the Best Way to Build a String of Delimited Items in Java
Why Is Spawning Threads in Java Ee Container Discouraged
Is There a Goto Statement in Java
How to Extract Numbers from a String and Get an Array of Ints
Where Does the @Transactional Annotation Belong
How to Convert Json to a Hashmap Using Gson
What Does ≪T≫ (Angle Brackets) Mean in Java
Including Jars in Classpath on Commandline (Javac or Apt)
Spring - @Transactional - What Happens in Background
When to Choose Checked and Unchecked Exceptions
Equals VS Arrays.Equals in Java