Rumid
Rumid

Reputation: 1709

How to provide Context with Dagger2

I am learning Android and I am following some guides for Retrofit2 with RxJava and Dagger2. Now I want to handle no internet connection case. I've found this answer, which seems to be elegant, but I do not understand how to apply it.

I've got some NetworkModule, with OkHttpClient provider. I assume I need to create OkHttpClient.Builder with interceptor. So it should look something like this: `

@Provides
@Singleton
OkHttpClient provideOkHttpClient(Cache cache) {
    ConnectivityInterceptor ci = new ConnectivityInterceptor(networkObservable()));
    OkHttpClient.Builder.addInterceptor(ci)
    return builder.build();
}

private boolean networkObservable() {
    ConnectivityManager cm =
            (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);

    NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
    return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}

This isn't working as I don't have Context. In which direction should I go - to try to obtain context there, or maybe I misunderstand the concept of observables?

Upvotes: 5

Views: 10667

Answers (3)

Paschalis
Paschalis

Reputation: 12291

Kotlin approach

You can provide the Application, which can be used to provide the `Context.

Define an AppComponent:

import android.app.Application
import dagger.BindsInstance
import dagger.Component
import javax.inject.Singleton

@Component
@Singleton
interface AppComponent {
  @Component.Builder
  interface Builder {
    fun build(): AppComponent

    @BindsInstance
    fun application(application: Application): Builder
  }
}

Extend Application like so:

abstract class MyApp : Application() {
    override fun onCreate() {
       super.onCreate()
       DaggerAppComponent.builder().application(this).build()
       // ..
    }
}

Upvotes: 4

Yida Lin
Yida Lin

Reputation: 187

Just wanted to supplement @anton-kazakov's answer, to provide a way to supply activity/service context in addition to application context:

ApplicationContext

import javax.inject.Qualifier;

@Qualifier
public @interface ApplicationContext {
}

ServiceScope

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import javax.inject.Scope;

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ServiceScope {
}

ApplicationModule

@Module
public class ApplicationModule {

    private MyApplication mMyApplication;

    public ApplicationModule(@NonNull MyApplication myApplication) {
        mMyApplication = myApplication;
    }

    @Singleton
    @Provides
    @NonNull
    @ApplicationContext
    public Context provideApplicationContext() {
        return mMyApplication;
    }
}

ServiceModule (or, activity etc.)

import dagger.Module;
import dagger.Provides;

@Module
public class ServiceModule {

    private final MyService mMyService;

    public ServiceModule(MyService myService) {
        mMyService = myService;
    }

    @ServiceScope
    @Provides
    public Context provideContext() {
        return mMyService;
    }
}

ApplicationComponent

import javax.inject.Singleton;

import dagger.Component;

@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {

    ServiceComponent newMyServiceComponent(ServiceModule serviceModule);

    // This is optional, just putting here to show one possibility
    void inject(BootCompleteReceiver bootCompleteReceiver);

}

ServiceComponent

import dagger.Subcomponent;

@ServiceScope
@Subcomponent(modules = {ServiceModule.class})
public interface ServiceComponent {

    void inject(MyService myService);

}

Application

public class MyApplication extends Application {

    private ApplicationComponent mApplicationComponent;

    @Override
    public void onCreate() {
        // mApplicationComponent = DaggerApplicationModule.builder()
        //         .applicationModule(new ApplicationModule(this))
        //         .build();
        super.onCreate();
    }

    /**
     * Note: {@link ContentProvider#onCreate} is called before 
     * {@link Application#onCreate}, hence if you have a 
     * {@link ContentProvider}, inject here instead of 
     * in {@link Application#onCreate}.
     * <p>
     * https://stackoverflow.com/a/44413873
     * <p>
     * https://stackoverflow.com/questions/9873669/how-do-i-catch-content-provider-initialize
     *
     * @param base The base Context.
     */
    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        mApplicationComponent = DaggerApplicationComponent.builder()
                .applicationModule(new ApplicationModule(this))
                .build();
    }

    public ApplicationComponent getApplicationComponent() {
        return mApplicationComponent;
    }
}

Service

import javax.inject.Inject;

public class MyService extends Service {

    @Override
    public void onCreate() {
        ((MyApplication) getApplicationContext())
                .getApplicationComponent()
                .newMyServiceComponent(new ServiceModule(this))
                .inject(this);
        super.onCreate();
    }
}

References

https://dagger.dev/api/2.19/dagger/Component.html https://dagger.dev/api/2.19/dagger/Module.html#subcomponents--

Upvotes: 1

Anton Kazakov
Anton Kazakov

Reputation: 2764

You can use the @Provides annotation in your DaggerModule to obtain application Context. Alternatively you can create a module which accepts a Context parameter in its constructor in case you need activity context. Then you can build the component in your activity and inject the arguments into it.

 @Module
public class AppModule {

    private Context context;

    public AppModule(@NonNull Context context) {
        this.context = context;
    }

    @Singleton
    @Provides
    @NonNull
    public Context provideContext(){
        return context;
    }

}

Application class:

public class PFApplication extends Application {

    private static AppComponent appComponent;

    public static AppComponent getAppComponent() {
        return appComponent;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        appComponent = buildComponent();
    }

    public AppComponent buildComponent(){
        return DaggerAppComponent.builder()
                .appModule(new AppModule(this))
                .build();
    }
}

Upvotes: 5

Related Questions