Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dagger2 error "android.app.Application cannot be provided without an @Inject constructor or from an @Provides-annotated method"

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.

like image 927
Daniel Gorgan Avatar asked Dec 22 '17 10:12

Daniel Gorgan


1 Answers

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.

like image 155
Jeff Bowman Avatar answered Nov 15 '22 03:11

Jeff Bowman