Using Dagger 2 to inject into service
Solution 1
I wrote the code from the top of my head, so there could be a typo or two.
You do it just the same as when injecting stuff into activities.
- Declare a component,
- add the inject method to that component,
- add a module providing your service
- create that components builder
- add your module to the builder
- inject your service with the component
Your module and component would look something like this (maybe add some scope)
@Module
class ServiceModule {
MyService mService;
ServiceModule(MyService service) {
mService = service;
}
@Provides
MyService provideMyService() {
return mService;
}
}
@Component(modules=ServiceModule.class)
interface MyServiceComponent {
void inject(MyService service);
}
Then in onCreate
just create your component and inject your alarm.
@Inject
private SomeAlarm alarm;
public void onCreate() {
DaggerMyServiceComponent.builder()
.serviceModule(new ServiceModule(this))
.build()
.inject(this);
alarm.doStuff();
}
This is assuming that your alarm can be constructor injected by having an @Inject
annotated constructor like this:
class SomeAlarm {
@Inject
SomeAlarm(MyService service) {
/*constructor stuff*/
}
}
Else you would just also add the alarm creation to your module.
Solution 2
I know this question already has an answer but there are an other way to do this
first make your application extend HasServiceInjector
like this:
public class App extends Application implements HasActivityInjector,
HasServiceInjector {
@Inject
DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
@Inject
DispatchingAndroidInjector<Service> dispatchingServiceInjector;
@Override
public void onCreate() {
super.onCreate();
AppInjector.init(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingActivityInjector;
}
@Override
public AndroidInjector<Service> serviceInjector() {
return dispatchingServiceInjector;
}
}
then create a ServiceBuilderModule
this will perform injection over services:
@Module
abstract class ServiceBuilderModule {
@ContributesAndroidInjector
abstract MyService contributeMyService();
}
then register the new module to your component
@Component(modules = {
AndroidSupportInjectionModule.class,
AppModule.class,
ActivityBuilderModule.class,
ServiceBuilderModule.class
})
@Singleton
public interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
Builder application(App application);
AppComponent build();
}
void inject(App app);
}
then override the onCreate
method of your service and add AndroidInjection.inject(this)
like below code :
public class MyService extends Service {
@Override
public void onCreate() {
AndroidInjection.inject(this);
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
code in kotlin
is exact conversion of the code above. hope this helps some coders from now on.
Ofek Agmon
Updated on February 29, 2020Comments
-
Ofek Agmon over 4 years
I have an app which is basically a service that runs all the time and alarms the user when something happens.
When the service creates the alarm, it needs to give it his
context
so that the alarm can do callbacks to the service when something happens.For example:
public MyService extends Service{ private SomeAlarm alarm; @Override public void onCreate() { super.onCreate(); alarm = new SomeAlarm(MyService.this); } }
How can I inject the
SomeAlarm
class into the service, and give theSomeAlarm
the service context as a variable? -
Ofek Agmon about 8 yearsthanks for your answer. the code wont compile, saying "Builder() has private access in Builder" when I am trying to inject the alarm
-
David Medenjak about 8 years@OfekAgmon This is why I added the first line in my answer. It is
DaggerMyServiceComponent.builder()
. -
Ofek Agmon about 8 yearsthanks, also I needed to take out the "new" before the DaggerMyServiceComponent.builder()
-
Paula Kristin over 7 yearsI hope it is ok to still ask a question but for me, everytime I make a new DaggerComponent I get the error of
cannot find symbol class
of my old dagger components during compilation. Anyone knows why? -
franta kocourek over 7 years@PaulaKristin you have to compile your project (modules or whatever) first. That Dagger* class is created by Dagger compiler. So you have to provide a way of adding Dagger's compiler output to your classpath.
-
user1510006 almost 5 yearsIs it possible to do the injection on the onHandleIntent instead of the onCreate method for intent service ?
-
David Medenjak almost 5 years@user1510006 In theory you can inject at any given time, but it should only happen once, and before you try to use any of the injected objects (or you'll get a NPE). Doing it right away in
onCreate
ensures all of these,onHandleIntent
can be called multiple times, so you'd have to add addtional checks -
AdamHurwitz over 4 yearsWhen injecting Dagger inside of a
Service
class does it matter whether theinit
call is made before or after thesuper.OnCreate()
call? i.e. For activities, it's important to be made before in case fragments are created from that activity. I'd expect aService
to be similar. -
David Medenjak over 4 years@AdamHurwitz I don't think it will matter for most cases since there is not much going on in
onCreate()
in services -
AllDayAmazing over 4 yearsAnyone figured out a way to do Service injection without field injection?
-
David Medenjak over 4 years@AllDayAmazing What would you like to do? You can use method injection which is similar to field injection, but since the Framework creates the Service you can't use constructor injection. Other than that you can always add a provision method to a component and grab your dependencies manually, using Dagger as a kind of service locator
-
AllDayAmazing over 4 years@DavidMedenjak thanks! Basically what I came up with - just was wondering if anyone knew of some hidden APIs or something that I was forgetting to make it possible to avoid field injection cleanly