web-dev-qa-db-fra.com

Dagger 2 injecting Android Context

J'utilise Dagger 2 et je le fais fonctionner, mais j'ai maintenant besoin d'accéder au contexte d'application Android.

Ce n'est pas clair pour moi comment injecter et accéder au contexte. J'ai essayé de le faire comme suit:

@Module
public class MainActivityModule {    
    private final Context context;

    MainActivityModule(Context context) {
        this.context = context;
    }

@Provides @Singleton
Context provideContext() {
    return context;
}

Cependant, cela entraîne l'exception suivante:

Java.lang.RuntimeException: impossible de créer l'application: Java.lang.IllegalStateException: mainActivityModule doit être défini

Si j'inspecte le code généré par Dagger, cette exception est déclenchée ici:

public Graph build() {  
    if (mainActivityModule == null) {
        throw new IllegalStateException("mainActivityModule must be set");
    }
    return new DaggerGraph(this);
}

Je ne sais pas si c'est la bonne façon d'injecter du contexte - toute aide sera grandement appréciée.

30
user3521637

Ne générait pas correctement le composant Application, nécessaire pour transmettre l'application. Cet exemple de Dagger 2 montre parfaitement comment procéder: https://github.com/google/dagger/tree/master/examples/Android-simple/src/main/Java/com/example/dagger/simple

Mise à jour:
Lien de travail: https://github.com/yongjhih/dagger2-sample/tree/master/examples/Android-simple/src/main/Java/com/example/dagger/simple

1
user3521637
@Module
public class MainActivityModule {    
    private final Context context;

    public MainActivityModule (Context context) {
        this.context = context;
    }

    @Provides //scope is not necessary for parameters stored within the module
    public Context context() {
        return context;
    }
}

@Component(modules={MainActivityModule.class})
@Singleton
public interface MainActivityComponent {
    Context context();

    void inject(MainActivity mainActivity);
}

Et alors

MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder()
    .mainActivityModule(new MainActivityModule(MainActivity.this))
    .build();
24
EpicPandaForce

Il m'a fallu un certain temps pour trouver une solution appropriée, alors j'ai pensé que cela pourrait faire gagner du temps aux autres, pour autant que je sache, c'est la solution préférée avec la version actuelle de Dagger (2.22.1).

Dans l'exemple suivant, j'ai besoin du ApplicationContext pour créer un RoomDatabase (se produit dans StoreModule).

S'il vous plaît, si vous voyez des erreurs ou des erreurs, faites-le moi savoir afin que j'apprenne aussi :)

Composant:

// We only need to scope with @Singleton because in StoreModule we use @Singleton
// you should use the scope you actually need
// read more here https://google.github.io/dagger/api/latest/dagger/Component.html
@Singleton
@Component(modules = { AndroidInjectionModule.class, AppModule.class, StoreModule.class })
public interface AwareAppComponent extends AndroidInjector<App> {

    // This tells Dagger to create a factory which allows passing 
    // in the App (see usage in App implementation below)
    @Component.Factory
    interface Factory extends AndroidInjector.Factory<App> {
    }
}

AppModule:

@Module
public abstract class AppModule {
    // This tell Dagger to use App instance when required to inject Application
    // see more details here: https://google.github.io/dagger/api/2.22.1/dagger/Binds.html
    @Binds
    abstract Application application(App app);
}

StoreModule:

@Module
public class StoreModule {
    private static final String DB_NAME = "aware_db";

    // App will be injected here by Dagger
    // Dagger knows that App instance will fit here based on the @Binds in the AppModule    
    @Singleton
    @Provides
    public AppDatabase provideAppDatabase(Application awareApp) {
        return Room
                .databaseBuilder(awareApp.getApplicationContext(), AppDatabase.class, DB_NAME)
                .build();
    }
}

App:

public class App extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();

        // Using the generated factory we can pass the App to the create(...) method
        DaggerAwareAppComponent.factory().create(this).inject(this);
    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
}
1
keisar