I'm trying to implement dagger2 in my project, but I'm faced with an error "android.app.Application cannot be provided without an @Inject constructor or from an @Provides-annotated method".
Here's my code:
App.java
package com.poppmedia.wallpaperautomaton;
import android.app.Application;
import com.poppmedia.wallpaperautomaton.di.DaggerAppComponent;
import dagger.android.AndroidInjector;
import dagger.android.DaggerApplication;
/**
* The Android {@link Application}.
*/
public class App extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
return DaggerAppComponent.builder().create(this);
}
}
di/AppModule.java
package com.poppmedia.wallpaperautomaton.di;
import android.app.Application;
import android.content.Context;
import javax.inject.Singleton;
import dagger.Binds;
import dagger.Module;
/**
* Provider application-wide dependencies.
*/
@Module
public interface AppModule {
@Binds
@Singleton
Context bindContext(Application application);
}
di/AppComponent.java
package com.poppmedia.wallpaperautomaton.di;
import com.poppmedia.wallpaperautomaton.App;
import javax.inject.Singleton;
import dagger.Component;
import dagger.android.AndroidInjector;
import dagger.android.support.AndroidSupportInjectionModule;
/**
* Injects application dependencies.
*/
@Singleton
@Component(modules = {
AndroidSupportInjectionModule.class,
AppModule.class,
})
public interface AppComponent extends AndroidInjector<App> {
@Component.Builder
abstract class Builder extends AndroidInjector.Builder<App> {}
}
di/TestClassModule.java
package com.poppmedia.wallpaperautomaton.di;
import android.content.Context;
import com.poppmedia.wallpaperautomaton.TestClass;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class TestClassModule {
@Provides
@Singleton
TestClass provideTestClass(Context context) {
return new TestClass(context);
}
}
di/TestClassComponent.java
package com.poppmedia.wallpaperautomaton.di;
import com.poppmedia.wallpaperautomaton.TestClass;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = { AppModule.class, TestClassModule.class })
public interface TestClassComponent {
TestClass getTestClass();
}
TestClass.java
package com.poppmedia.wallpaperautomaton;
import android.content.Context;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class TestClass {
private Context mContext;
@Inject
public TestClass(Context context) {
mContext = context;
}
}
Thank you.
In your specific case, you're missing:
@Binds Application bindApplication(App app);
This is important because dagger.android will automatically include a binding to the specific Application, Activity, Fragment, Service, BroadcastReceiver, etc subclass but not the general object. (You'd be able to inject App but not Application, and YourActivity but not Activity.) If you want to indicate to dagger.android that it should fulfill requests for Application using your App instance, you have to include a binding as above.
Generally speaking, this is a pretty safe thing to do for Application, Activity, Service, and BroadcastReceiver, but not Fragment (native or in the compat libraries); this is because dagger.android respects nested fragments, and in that case it would be ambiguous which Fragment to inject.
Though you can provide the Application through a Module and instance field as in luffy's answer, this is more boilerplate than you need, and is also less optimized: Dagger will write code to call your @Provides
method, whereas you can declaratively tell Dagger to reuse an existing binding using @Binds
or write a static @Provides
method that avoids invoking the call on an instance.
See the Dagger advantages of @Binds
and the Android advantages of static dispatch.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With