NightFury
NightFury

Reputation: 13546

Inject dependencies into Singleton Dagger 2.11

I have application-level scoped Singleton classes TaskRepository and AppConfig, which have dependencies of singleton types. In my activity, instance of TaskRepository is injected, but all its fields are null.

Application Class

public class MVPApplication extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> activityDispatchingAndroidInjector;

    @Inject
    TasksRepository tasksRepository;

    @Inject
    AppConfig appConfig;

    private static MVPApplication instance;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        Realm.init(this);
        DaggerAppComponent
                .builder()
                .application(this)
                .realmBuilder(Realm.getDefaultInstance())
                .build()
                .inject(this);
    }

    @Override
    public DispatchingAndroidInjector<Activity> activityInjector() {
        return activityDispatchingAndroidInjector;
    }
}

AppComponent

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AppModule.class,
        ActivityBindingModule.class})
public interface AppComponent extends AndroidInjector<DaggerApplication> {

    @Component.Builder
    interface Builder {

        @BindsInstance
        Builder application(Application application);

        @BindsInstance
        Builder realmBuilder(Realm realm);

        AppComponent build();
    }

    void inject(MVPApplication application);

    TasksRepository getRepository();

    AppConfig getAppConfig();

}

AppModule

@Singleton
@Module
public class AppModule {

@Provides
@Singleton
TasksRepository provideTasksRepository() {
    return new TasksRepository();
}

@Provides
@Singleton
AppConfig provideAppConfig() {
    return new AppConfig();
}
}

TaskRepository Class

@Singleton
public class TasksRepository implements RepositoryDatasource {

@Inject
Context mContext;

@Inject
AppConfig appConfig; //Singleton

@Inject
Realm realm; //Singleton

   //There is no constructor. Only public functions using fields

}

AppConfig Class

@Singleton
public class AppConfig {

    @Inject
    Context mContext;

   //There is no constructor. Only public functions using fields
}

Please highlight my mistakes... Any help will be appreciated. Thanks!

Upvotes: 1

Views: 1890

Answers (1)

David Rawson
David Rawson

Reputation: 21497

There are two main types of injection with Dagger 2 - field injection and constructor injection. Field injection is where you annotate fields of a class like an Activity or Fragment with @Inject and then explicitly request injection from a Dagger 2 Component:

 class MainActivity extends AppCompatActivity {

     @Inject TasksRepository tasksRepository;

     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         AndroidInjector.inject(this); //explicit request for injection
     }
 }

Note that without the explicit request for injection in line 2 of onCreate the field tasksRespository would remain null.

For classes instantiated by the Android OS like Activity or Application field injection is appropriate. For others, including your repositories, it is preferable to use constructor injection. Why? When you are testing you can pass in test doubles through the constructor and stub behaviour or verify on the test doubles.

So to get it working you should refactor your TasksRepository to use constructor injection:

@Singleton
public class TasksRepository implements RepositoryDatasource {

    private final Context context;
    private final AppConfig appConfig; 
    private final Realm realm;

    @Inject
    TasksRepository(Context context, AppConfig appConfig, Realm realm) {
        this.context = context;
        this.appConfig = appConfig;
        this.realm = realm;
    }

Note that this step will highlight any mistakes you have made in setting up your object graph. So if Dagger 2 cannot provide any of the 3 parameters in the construtor for TasksRepository it will let you know with a compile-time message.

Upvotes: 4

Related Questions