0

I am using dependency injection according to google sample

The only external dependency I can pass is through AppComponent builder

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AppModule.class,
        MainTabActivityModule.class,
        CoreActivityModule.class
})
public interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Application application);
        AppComponent build();
    }
    void inject(MyApplication myApplication);
}

and injected in app like this

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

DaggerAppComponent
                .builder()
                .application(myApplication)
                .build().inject(myApplication);
...
}

According to document injecting in Activity looks like this. I added what I would like to achieve.

public class YourActivity extends Activity {
  public void onCreate(Bundle savedInstanceState) {
    AndroidInjection
//.builder()                 THIS IS WHAT I WANT TO ACHIEVE
//.addActivityContext(this)  THIS IS WHAT I WANT TO ACHIEVE
//.build()                   THIS IS WHAT I WANT TO ACHIEVE
.inject(this);
    super.onCreate(savedInstanceState);
  }
}

but the question is how can I add additional parameter to subComponent.

@Subcomponent
public interface CoreActivitySubComponent extends AndroidInjector<CoreAppActivity> {
//    @Subcomponent.Builder
//    interface Builder {
//        Builder addContext(Context context) //did not work
//        CoreActivitySubComponent build();   //did not work
//    }

//==or using abstract class
//   in this option I do not know where to add parameter to this builder
    @Subcomponent.Builder
    public abstract class Builder extends AndroidInjector.Builder<CoreAppActivity> {


    }

}
Malbac
  • 197
  • 1
  • 1
  • 12
  • Please include the specific error you're facing, because "doesn't work" is rather vague. Did you use the right method names? You once call it `addActivityContext` and the other time `addContext` – David Medenjak Oct 28 '17 at 20:29
  • This is not about error. I would like achieve state in Dagger 2, when Activity is injected using method AndroidInjection.inject(this); I want to add external dependecy, I want to add Activity Context. So I can @Inject object which requires Context in constructor – Malbac Oct 28 '17 at 20:38
  • Maybe you are looking for overriding the `seedInstance` method? Have a look at [this question](https://stackoverflow.com/questions/43371863/dagger-2-10-android-subcomponents-and-builders) – David Rawson Oct 29 '17 at 23:36
  • 1
    Yes, you right. Thats what I was looking for. I was able to achieve it also by @Bind annotation, according to https://android.jlelse.eu/android-and-dagger-2-10-androidinjector-5e9c523679a3 – Malbac Oct 30 '17 at 06:58

2 Answers2

0

The problem was that Dagger 2.1.0 method AndroidInjection.inject(this); which is supposed to be used in Activity and Fragment, do not provide any builder to add external dependency.

I wanted to create general module which depends on Activity/Fragment context.

sample:

public class ToastController {

    private Context context;

    @Inject
    public ToastController(Context context) {
        this.context = context;
    }

    public void showToast(@StringRes int res) {
        Toast.makeText(context, context.getText(res), Toast.LENGTH_SHORT).show();;
    }
}

But I was not able to generalize it to the level, that I could provide just one context modude, instead I had to do create binds module for every single Activity/ Fragment that uses this module.

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AppModule.class,
        MainTabActivityModule.class,// IMPORTANT CLASS
})
public interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(Application application);
        AppComponent build();
    }
    void inject(MyApplication myApplication);
}

This is a place, where I provide context module for each Activity

@Module
public abstract class MainTabActivityModule 
    @ContributesAndroidInjector(modules = ContextMainTabActivityModule.class)//THIS MODULE
    abstract MainTabActivity contributeMainActivity();

}

and Context is provided using @Binds annotation

@Module
public abstract class ContextMainTabActivityModule {
    @Binds
    abstract Context provideContext(MainTabActivity featureActivity);
}

=====================

It can be done by overriding method seedInstance according to sample

I tried this, but it did not work for me

@Subcomponent.Builder
    public abstract class Builder extends AndroidInjector.Builder<CoreAppActivity> {

        abstract Builder addContextModule(ContextModule contextModule);

        @Override
        public void seedInstance(CoreAppActivity instance) {
            addContextModule(new ContextModule(instance));
        }
    }

next class

@Module
public class ContextModule {

    private CoreAppActivity coreAppActivity;

    @Provides
    Context getContext() {
        return coreAppActivity.getBaseContext();
    }

    public ContextModule(CoreAppActivity coreAppActivity) {
        this.coreAppActivity = coreAppActivity;
    }

}
Jason Robinson
  • 31,005
  • 19
  • 77
  • 131
Malbac
  • 197
  • 1
  • 1
  • 12
0

Did you add the ContextModule to your @Subcomponent similar to this answer? I think your @Subcomponent should look something like this:

@Subcomponent(module = {ContextModule.class})
interface MainTabActivityComponent extends AndroidInjector<CoreAppActivity> {
    @Subcomponent.Builder
    public abstract class Builder extends AndroidInjector.Builder<CoreAppActivity> {

        abstract Builder addContextModule(ContextModule contextModule);

        @Override
        public void seedInstance(CoreAppActivity instance) {
            addContextModule(new ContextModule(instance));
        }
    } 
}

And finally don't forget to include this @Subcomponent in your binding-module.

One last question: is this really required? I found that using the AndroidInjector on the Application as well as Activities and Fragments will give me the correct corresponding Context when I inject it.

Jan
  • 1
  • 3
  • I went through this post already. However the context was not provided, in spite of the fact that class requiring context extends CoreAppActivity. This works, when you create builder for particular Activity directly, but that you end up with ContextModule for every single Activity and it is exactly what I want to avoid – Malbac Oct 31 '17 at 11:19