Dependency injection in a scheduled JobService with Dagger 2

1.7k views Asked by At

What's the best way to inject dependencies in a scheduled jobservice in Android. My JobService is scheduled to run in the night to do some stuff.

In JobService constructor i'm trying to inject my dependencies over my Application class.

MyApp.component().inject(this);

But sometimes MyApp isn't initialized at this time and so the injection failes.

Maybe i'm using Dagger in a wrong way? Or do i have to create an own component for the JobService?

Here is my Application class

public class MyApp extends Application {
  private static AppComponent appComponent;

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

    buildAppComponent();

  }

  public static AppComponent component(){
    return appComponent;
  }

  private void buildAppComponent(){
    if(appComponent == null){
        appComponent = DaggerAppComponent.builder()
            .appModule(new AppModule(this))
            .build();
    }
  }
}
1

There are 1 answers

2
Samuel Eminet On

You should use AndroidInjector to inject android classes such as Activities/Fragments/Services/BroadcastReceivers/ContentProviders.

First make sure you added dagger-android dependency from your build.gradle

implementation 'com.google.dagger:dagger:2.16'
implementation 'com.google.dagger:dagger-android:2.16'
implementation 'com.google.dagger:dagger-android-support:2.16'
annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
annotationProcessor 'com.google.dagger:dagger-android-processor:2.16'

Then make sure you app component inherit from AndroidInjector

@Singleton
@Component(modules = {AndroidSupportInjectionModule.class,
                      ApplicationModule.class,
                      ActivityBuilderModule::class,
                      ServiceBuilderModule::class})
public interface ApplicationComponent extends AndroidInjector<MyApp> {
    @Component.Builder
    interface Builder {
        @BindsInstance
        Builder application(MyApp application);

        ApplicationComponent build();
    }
}

ActivityBuilderModule and ServiceBuilderModule reference all you activitiy and service subcomponents using an handy annotation ContributesAndroidInjector that will generate the subcomponent automatically for you

@Module
abstract class ActivityBuilderModule {
    @ContributesAndroidInjector(modules = {MainActivityModule.class})
    @ActivityScope
    abstract MainActivity contributeMainActivity();

    @ContributesAndroidInjector(modules = {DummyModule.class})
    @ActivityScope
    abstract DummyActivity contributeDummyActivity();

    //...
}

same for services

@Module
abstract class ServiceBuilderModule {
    @ContributesAndroidInjector
    abstract MyService contributeAuthenticatorService();

    //...
}

Finally here how your MyApp should look like

public class MyApp extends DaggerApplication() {
    private ApplicationComponent appComponent;

    @Override
    public void onCreate() {
        super.onCreate();
        appComponent = DaggerApplicationComponent.builder()
                                                  .application(this)
                                                  .build();
    }

    AndroidInjector<? extends DaggerApplication> applicationInjector(){
        return appComponent;
    }
}

Your service should now be injectable, to wrap this up you'll certainly want to inject fragments as well so for example for MainActivity fragments you'll make a FragmentBuilderModule from your MainActivityModule

@Module(includes = {FragmentBuilderModule.class})
abstract class MainActivityModule {
    @Binds
    @ActivityScope
    abstract AppCompatActivity bindActivity(MainActivity activity);

    //...
}

and here the FragmentBuilderModule class

@Module
abstract class FragmentBuilderModule {
    @ContributesAndroidInjector(modules = {HomeFragmentModule.class})
    @FragmentScope
    abstract HomeFragment contributeHomeFragment();

    @ContributesAndroidInjector(modules = DummyFragmentModule.class})
    @FragmentScope
    abstract DummyFragment contributeDummyFragment() ;

    //...
}

You can see more from my project template here though it's kotlin.