DimKe
DimKe

Reputation: 43

Can't provide Activity Context with Dagger 2

SOLVED

I am new with Dagger 2 and I am trying to provide Activity Context to classes but without success. I search a lot but did not find any appropriate answer.

I can provide Application Context. But I also need to provide Activity Context as well and I don't know any good way to implement that.

I need to clarify that I am using Dagger for Android dependencies.

def dagger_version = "2.24"
implementation "com.google.dagger:dagger:$dagger_version"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
implementation "com.google.dagger:dagger-android:$dagger_version"
implementation "com.google.dagger:dagger-android-support:$dagger_version"
annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"

I also have only an AppComponent with the following code:

@Singleton
@Component(
        modules = {
                AndroidSupportInjectionModule.class,
                ActivityBuildersModule.class,
                AppModule.class,
                ViewModelFactoryModule.class,
        }
)
public interface AppComponent extends AndroidInjector<BaseApplication> {

    SessionManager sessionManager();

    @Component.Builder
    interface Builder{

        @BindsInstance
        Builder application(Application application);

        AppComponent build();
    }
}

Except that I have a module for each of my activity but I didn't find a way to inject the Activity Context either for AppComponent or from a ActivityModule.

What is the right way to do that?

UPDATE

I finally found the right way to do that.

First I created a module for the class that I want to provide

@Module
public class AlertsModule {

    @Provides
    static Alerts provideAlerts(Activity activity){
        return new Alerts(activity);
    }

}

Then I go to the ActivityModules that I want to Inject that custom Class and do a Binding like that

@Module
public abstract class MainActivityModule {

    ...

    @Binds
    abstract Activity providesActivity(MainActivity activity);

    ...

}

And finally I just include the CustomClassModule in my ActivityBuildersModule where I use @ContributesAndroidInjector to provide my Activities.

    @MainScope
    @ContributesAndroidInjector(
            modules = {
                    AlertsModule.class,
            }
    )
    abstract MainActivity contributeMainActivity();

Upvotes: 3

Views: 2162

Answers (3)

Sandi
Sandi

Reputation: 2731

You can bind an instance of Activity in the same way you're currently binding an instance of Application, either by using an @Component.Builder or an @Component.Factory.

An example implementation would look something like this:

@Subcomponent(...)
interface ActivitySubcomponent {

    @Subcomponent.Factory
    interface Factory {
        ActivitySubcomponent create(@BindsInstance MyActivity activity)
    }
}
@Module(subcomponents = [ActivitySubcomponent.class])
class ApplicationModule {
    ....
}
public class MyActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        ...
        ((MyApplication) getApplication())
            .applicationComponent
            .activitySubcomponentFactory()
            .create(this)
            .inject(this)
    }
}

Upvotes: 4

Arun Gohil
Arun Gohil

Reputation: 61

@Named annotation helps us to differentiate the Context. We can differentiate the method context() in ActivityModule and ContextModule by adding the @Named annotation as below:

@Module
public class ActivityModule {
    private final Context context;

    ActivityModule(Activity context){
        this.context = context;
    }

    @Named("activity_context")
    @Provides
    public Context context(){ return context; }
}

@Module
public class ContextModule {
    private final Context context;

    ActivityModule(Activity context){
        this.context = context;
    }

    @Named("application_context")
    @Provides
    public Context context(){ return context.getApplicationContext(); }

Then, we tell Dagger to use the respective Context, as below:

@Module(includes = ContextModule.class)
public class OkHttpClientModule {
    ....
    @Provides
    public File file(@Named("application_context") Context context){
    File file = new File(context.getCacheDir(), "HttpCache");
    file.mkdirs();
    return file;
    }
    ....
}

Hope this helps.

Upvotes: 0

Atif AbbAsi
Atif AbbAsi

Reputation: 6035

@Module
class MainActivityModule(mActivity: MainActivity) {

    var mActivity: MainActivity


    init {
        this.mActivity= mActivity
    }


    @Singleton
    @Provides
    fun getMainActivity(): MainActivity{
        return mActivity
    }


}

now add this module to your Component class and pass your activity to module constructor while using your component builder hope this may helps you.

Upvotes: 0

Related Questions