Dagger: proper way to define injectable class that

2019-07-04 00:17发布

问题:

I want to use dagger (dagger v1 by Square) to create a singleton class whose constructor requires context as an argument. I then want to inject this singleton class into my MainActivity. What are the proper steps to define this?

I tried doing this:

SingletonClass:

@Module(
    injects = {MainActivity.class}
)
@Singleton
public class SingletonClass {
...

@Inject
SingletonClass(Context ctx) {}
}

to which I receive the error:

no injectable members on android.content.Context

I understand that SingletonClass is supposed to receive it's context from somewhere in order to be injectable, but since I'm not "calling" it anymore in the traditional sense, but rather I'm injecting it like so in the MainActivity at the class-level:

@Inject SingletonClass singletonClass;

how am I supposed to pass it the context?

Here are additional files I created for dagger (two of which I saw used in official examples):

AndroidModule:

@Module(library = true, injects = MainActivity.class)
public class AndroidModule {

private final Context context;

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

/**
 * Allow the application context to be injected but require that it be
 * annotated with to explicitly
 * differentiate it from an activity context.
 */
@Provides
@Singleton
@ForApplication
Context provideApplicationContext() {
    return context;
}


}

App.class (to extend my application):

public class App extends Application {
private static final String TAG = App.class.getSimpleName();
private static App instance;
public MainActivity mainActivity;
private static Context context;
private ObjectGraph objectGraph;

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

    instance = this;
    context = getApplicationContext();

    objectGraph = ObjectGraph.create(getModules().toArray());
}

public static App getInstance() {
    return instance;
}

public static Context getContext() { return context; }

protected List<Object> getModules() {
    return Arrays.asList(new AndroidModule(this), new App());
}

public void inject(Object object) {
    objectGraph.inject(object);
}
}

ForApplication class:

import java.lang.annotation.Retention;
    import javax.inject.Qualifier;

    import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Qualifier @Retention(RUNTIME)
public @interface ForApplication {
}

回答1:

You need to add the @ForApplication qualifier to your Context parameter in the SingletonClass constructor.

Dagger is now looking for a Context to inject, but only has a @ForApplication Context, which is a mismatch.

@Singleton
public class SingletonClass {

    @Inject
    SingletonClass(@ForApplication Context ctx) {
    }

}

Now you can also get rid of the library = true line in your AndroidModule, which you've probably added because Dagger warned you that @ForApplication Context was unused (Don't ignore these warnings!).

Also, and that might just be a copy-paste error, this SingletonClass should not have an @Module annotation.