Components should be a "large DI provider" that provides everything for a specific area.
For example, you might have a SingletonComponent area with an @Singleton tag, in which each individual module that has at least one @Singleton provider method has been @Singleton .
@Singleton @Component(modules={NetworkingModule.class, DatabaseModule.class, MapperModule.class, UtilsModule.class}) public interface SingletonComponent { // provision methods OkHttpClient okHttpClient(); RealmHolder realmHolder(); // etc. }
In the module, submission methods can be defined.
public interface DatabaseComponent { RealmHolder realmHolder(); } public interface NetworkingComponent{ OkHttpClient okHttpClient(); }
In this case you will have
@Singleton @Component(modules={NetworkingModule.class, DatabaseModule.class, MapperModule.class, UtilsModule.class}) public interface SingletonComponent extends NetworkingComponent, DatabaseComponent, MapperComponent, UtilsComponent {
In the module, you can specify a factory method (the "provider method") that indicates how to create a specific type of dependency.
For example,
@Module public class NetworkingModule { @Provides @Singleton OkHttpClient okHttpClient() { return new OkHttpClient.Builder()..build(); } @Provides @Singleton Retrofit retrofit(OkHttpClient okHttpClient) {
You can think of the @Singleton as a large DI container that Spring would provide you with.
You can also provide class instances using the annotated @Inject . This can get any class from a component that can instantiate it from provider methods within these modules with a scope (and, of course, regardless of conditions).
@Singleton public class MyMapper { @Inject public MyMapper(RealmHolder realmHolder, OkHttpClient okHttpClient) {
or
@Singleton public class MyMapper { @Inject RealmHolder realmHolder; @Inject OkHttpClient okHttpClient; @Inject public MyMapper() { } }
Then it will be available in the component, you can even make a provisioning method for it so that it is inherited in the component dependencies:
@Singleton @Component(modules={...}) public interface SingletonComponent { MyMapper myMapper(); }
With Dagger2, you can also create “copied components” that inherit all the dependencies provided by a component in a given area.
For example, you can inherit all @Singleton components, but still you still have new dependent scopes for the new scope, for example @ActivityScope .
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { }
You can then create sub-copied components using either subcomponents or component dependencies.
.
@ActivityScope @Subcomponent(modules={MainActivityModule.class}) public interface MainActivityComponent { MainPresenter mainPresenter(); }
This can then be created in a component with parent scope:
@Singleton @Component(modules={...}) public interface SingletonComponent { MainActivityComponent mainActivityComponent(MainActivityModule module); }
Then you can use the singleton component to create it:
SingletonComponent singletonComponent = DaggerSingletonComponent.create(); MainActivityComponent mainActivityComponent = singletonComponent.mainActivityComponent(new MainActivityModule(mainActivityHolder));
.
@ActivityScope @Component(dependencies={SingletonComponent.class}, modules={MainActivityModule.class}) public interface MainActivityComponent extends SingletonComponent { MainPresenter mainPresenter(); }
For this to work, you must specify the rendering methods in the super-copied component.
Then you can create an instance like this:
SingletonComponent singletonComponent = DaggerSingletonComponent.create(); MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder() .singletonComponent(singletonComponent) .mainActivityModule(new MainActivityModule(mainActivityHolder)) .build();
In Dagger2, you can get dependencies either through:
@Inject annotated constructor options@Inject annotated fields in classes with @Inject annotated constructor- from
@Component provisioning methods - using the manual input method in the field defined in the component (for classes that cannot be created using the constructor with
@Inject annotation)
Manually enabling classes, such as MainActivity , can be done manually.
Manual entry only introduces the specific class that you enter. Base classes are not automatically entered; they must call .inject(this) on the component.
It works as follows:
@ActivityScope @Subcomponent(modules={MainActivityModule.class}) public interface MainActivityComponent { void inject(MainActivity mainActivity); }
Then you can do:
public class MainActivity extends AppCompatActivity { @Override public void onCreate(Bundle bundle) { super.onCreate(bundle); MainActivityComponent mainActivityComponent = DaggerMainActivityComponent.builder() .singletonComponent(getSingletonComponent()) .mainActivityModule(new MainActivityModule(this)) .build();