Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Injecting dependencies into background service in Dagger2

I have Shared Preferences as a dagger singleton component. I need to inject it into background services like FirebaseInstanceService. Here's my attempt:

public class InstanceIDListenerService extends FirebaseInstanceIdService {
    @Inject
    Preferences preferences;

    @Override
    public void onTokenRefresh() {
        ((MyApp) getApplication()).getSingletonComponent().inject(this);
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        preferences.setFcmToken(refreshedToken);

    }
}

It is used in this way:

   <service android:name="com.fcm.InstanceIDListenerService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
   </service>

Should I use ((MyApp) getApplication()).getSingletonComponent().inject(this); in the onTokenRefresh listener? Is this the correct listener to inject dependencies?

like image 523
RedGiant Avatar asked Nov 14 '16 09:11

RedGiant


People also ask

What does @inject do Dagger?

With the @Inject annotation on the constructor, we instruct Dagger that an object of this class can be injected into other objects. Dagger automatically calls this constructor, if an instance of this class is requested.

How does Dagger dependency injection work?

Dagger automatically generates code that mimics the code you would otherwise have hand-written. Because the code is generated at compile time, it's traceable and more performant than other reflection-based solutions such as Guice. Note: Use Hilt for dependency injection on Android.


1 Answers

I know this question is old, but I've just been hitting my head on this over the last few hours, and found the solution.

With the new Dagger2 version, you can now have your application implement the HasServiceInjector interface, which lets you inject stuff into services.

A simple example:

1) Create your services module:

@Module
abstract class ServicesModule {

  @ContributesAndroidInjector
  abstract SomeService ProvideSomeService();
}

2) Add it to your App component:

@Component(modules = {
  AndroidSupportInjectionModule.class,
  AppModule.class,
  ActivitiesModule.class,
  ServicesModule.class
})
public interface AppComponent {

  @Component.Builder
  interface Builder {
    @BindsInstance
    Builder application(App application);

    AppComponent build();
  }

  void inject(App app);
}

3) Have your application implement the said interface:

public class App extends Application implements HasActivityInjector, HasServiceInjector {

  @Inject
  DispatchingAndroidInjector<Activity> activityInjector;
  @Inject
  DispatchingAndroidInjector<Service> serviceInjector;

  @Override
  public void onCreate() {
    super.onCreate();
    AppInjector.init(this);
  }

  @Override
  public AndroidInjector<Activity> activityInjector() {
    return activityInjector;
  }

  @Override
  public AndroidInjector<Service> serviceInjector() {
    return serviceInjector;
  }
}

4) Finally, inject your service:

public class SomeService extends Service {

  @Inject
  SomeDependency dependency;

  @Override
  public void onCreate() {
    AndroidInjection.inject(this);
    super.onCreate();
  }

  // Do things with your dependencies

}

I'm using a Service in the example, but my actual use case was with FirebaseInstanceIdService as well. And this worked.

like image 121
Ricardo Costeira Avatar answered Sep 27 '22 19:09

Ricardo Costeira