ZOFTINO.COM android and web dev tutorials

Dagger Subcomponents

Dagger subcomponents are components using which you can access objects of both parent component and subcomponent. Dagger subcomponents allow you to modularize your application’s dagger dependency injection configuration leading to partitioned object graph. Partitioning of object graph with subcomponent feature makes it possible to associates objects to a scope so that once the lower level scope become inactive, objects from that scope will be removed from memory while higher level or parent scoped objects continue to exist in memory and available for use.

For example in android applications, you can define parent component for application level use, subcomponents for activity and fragment level use. Fragment level component can provide or inject objects from both activity and application scoped parent components. Once fragment is destroyed, object defined for that scope will be removed.

I’ll explain how to create dagger subcomponents and use it in android application by taking coupons app. The example will have one activity and two fragments. Parent scope will be defined for activity and two child scopes for two fragments.

If you are new to dagger or need information about dagger, you can read dagger 2 examples article.

Defining Subcomponent Scope

You can define custom scope to associate a dagger component with it. In our example, we need to define two scopes for each fragment.

@Scope
@Retention(value= RetentionPolicy.RUNTIME)
public @interface CouponScope {
} 

Defining Subcomponent Modules

You need to define modules for subcomponents if needed and annotate provides method with the scope that you want subcomponents to be associated with.

 @Module
public class CouponModule {
    @CouponScope
    @Provides
    public CouponApi getCouponClient(Retrofit retrofit){
        return retrofit.create(CouponApi.class);
    }
    @CouponScope
    @Provides
    public CompositeDisposable getComposite(){
        return new CompositeDisposable();
    }
}
 

Defining Subcomponents

Subcomponents are defined like components. For subcomponents, you need to use Subcomponent annotation listing modules. You need to define Subcomponent.Builder interface providing builder method for each module and build method that returns component.

You can also define inject methods in subcomponents which can inject dependent objects from parent and subcomponents into target class.

 @CouponScope
@Subcomponent(modules = CouponModule.class)
public interface CouponComponent {
    public void inject(ToCouponFragment fragment);
    @Subcomponent.Builder
    interface Builder {
        Builder couponModule(CouponModule module);
        CouponComponent build();
    }

}
 

Defining Parent Component Module

In the parent component module, you need to list subcomponents using subcomponents attribute of Module annotation.

@Module(subcomponents = {CouponComponent.class, StoreComponent.class})
public class AppModule {
    public static final String BASE_URL = "http://www.zoftino.com/api/";

    @Singleton
    @Provides
    public Retrofit getRemoteClient(){
        return new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build();
    }
}

Defining Parent Component

In the parent component, you need to expose subcomponent builders. You can define inject methods in parent component also.

 @Singleton
@Component(modules={AppModule.class})
public interface AppComponent {
    CouponComponent.Builder couponBuilder();
    StoreComponent.Builder storeBuilder();
    public void inject(MainActivity mainActivity);
}
 

Injecting Objects from Parent Component Only

You can create or build parent component and use it to inject object from only parent component.

 public class MainActivity extends AppCompatActivity {
    @Inject
    StoreMessage storeMessage;

    private FragmentManager fm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

       DaggerAppComponent.create().inject(this);
 

Injecting Objects from Subcomponents

You can inject objects from both parent and subcomponents using subcomponent. You can create subcomponent using subcomponent builder method exposed in parent component.

 public class ToCouponFragment extends Fragment {

    @Inject
    CompositeDisposable compositeDisposable;
    @Inject
    CouponApi couponApi;
    @Inject
    StoreMessage storeMessage;

    private TextView cpn;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        DaggerAppComponent.create().couponBuilder().build().inject(this);

        View view = inflater.inflate(R.layout.tocoupon,
                container, false);
        cpn = (TextView) view.findViewById(R.id.couponInfo);
        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        compositeDisposable.add(io.reactivex.Observable.just(1)
                .subscribeOn(Schedulers.computation())
                .flatMap(i -> { return couponApi.getTopCoupon();}).subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Coupon>() {
                    @Override
                    public void accept(Coupon coupon) throws Exception {
                        cpn.setText(storeMessage.getMsgCoupon()+" "+coupon.toString());
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Log.e("ToCouponFragment", "exception getting coupon", throwable);
                    }
                }));
    }
    @Override
    public void onDestroy(){
        super.onDestroy();
        if(compositeDisposable.isDisposed()){
            compositeDisposable.clear();
        }
    }
}
 

You can download complete project from github at https://github.com/srinurp/DaggerSubcomponents