Is it possible to Inject object exposed through dagger into android.app.IntentService?
If so, how I can do that?
I want to have something like that.
public class SomeService extends android.app.IntentService {
#Inject
Synchronizer synchronizer;
public SomeService(String name) {
super(name);
}
#Override
protected void onHandleIntent(Intent intent) {
synchronizer.doSynch();
}
}
From a dagger point of view, IntentService isn't different from any other class.
However Dagger 2.x provides a new way, how you can inject dependencies into Android's base building element (like Service, Activities, Fragment etc.). Here sample calls for both versions.
Dagger 1.x
Injection can look like that (I'm assuming, that your Application has an instance of ObjectGraph and exposes method inject). Of course, don't forget add the class into a injected classes list in your Module definition.
public class SomeService extends android.app.IntentService {
#Inject
Synchronizer synchronizer;
public SomeService(String name) {
super(name);
}
#Override
public void onCreate() {
super.onCreate();
((YourApplication) getApplication()).inject(this);
}
#Override
protected void onHandleIntent(Intent intent) {
synchronizer.doSynch();
}
}
Dagger 2.10+
Dagger 2.10 has introduced AndroidInjection so no further dependency on the concrete Application instance is required.
public class SomeService extends android.app.IntentService {
#Inject
Synchronizer synchronizer;
public SomeService(String name) {
super(name);
}
#Override
public void onCreate() {
super.onCreate();
AndroidInjection.inject(this);
}
#Override
protected void onHandleIntent(Intent intent) {
synchronizer.doSynch();
}
}
Related
I am trying to make an injection using Dagger 2, but it always returns null. I think I am doing all right, but anyway it does not work.
Here is the application class:
public class ApplicationSA extends Application {
private static AppComponent appComponent;
#Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.create();
}
public static AppComponent getComponent() {
return appComponent;
}
}
The component interface:
#Component(modules = {
SnoreDetectorClass.class,
AudioRecorderClass.class
})
public interface AppComponent {
void injectsMainFunctionalityActivity(Activity activity);
}
An the main class where I am trying to get the object:
public class MainFunctionalityActivity extends AppCompatActivity {
#Inject
AudioRecorderClass audioRecorderClass;
#Inject
SnoreDetectorClass snoreDetectorClass;
#Override
protected void onCreate(Bundle savedInstanceState) {
ApplicationSA.getComponent().injectsMainFunctionalityActivity(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("TESTING","audioRecorderClass= "+audioRecorderClass); // always null
Log.d("TESTING","snoreDetectorClass= "+snoreDetectorClass); // always null
...
}
And here are the module classes:
#Module
public class AudioRecorderClass {
public interface AudioRecorderInterface {
void AudioRecorder_hasUpdate(double amplitude_in_dB);
}
public AudioRecorderInterface delegate = null;
#Provides
AudioRecorderClass provideAudioRecorderClass(Activity activity) {
delegate = (AudioRecorderInterface)activity;
return new AudioRecorderClass();
}
...
#Module
public class SnoreDetectorClass {
#Provides
SnoreDetectorClass provideSnoreDetectorClass() {
return new SnoreDetectorClass();
}
...
What am I doing wrong ? Why the objects are always null ?
Ah, I see what is going on here. You cannot inject into a subclass. So in your AppComponent you cannot have
void injectsMainFunctionalityActivity(Activity activity);
you must inject with
void injectsMainFunctionalityActivity(MainFunctionalityActivity activity);
As a side note I would suggest not combining your injector and your model class. Better to have separation of concerns. Keep them separate
You have to specifically tell dagger which activity will be injected here, not use the super class Activity but rather your own implementation of the Activity class :
void injectsMainFunctionalityActivity(Activity activity);
change to:
void injectsMainFunctionalityActivity(MainFunctionalityActivity activity);
I'm new to Dagger2 and I'm trying to use dependency injection in my application.
I'm using shared preferences and thought it will be more helpful to use dependency injection instead of getting an instance of shared prefrences each time I need to use it.
It works fine when I'm using it on activities and fragments but when I'm trying to use it on service or intentservice it doesn't work.
Here is my code:
AppModule:
#Module
public class AppModule
{
public final ApplicationClass application;
public AppModule(ApplicationClass application)
{
this.application = application;
}
#Provides #Singleton
Context providesApplicationContext()
{
return this.application;
}
#Provides #Singleton
SharedPreferences providesSharedPreferences()
{
return application.getSharedPreferences(Constants.FILE_NAME,Context.MODE_PRIVATE);
}
}
AppComponent
#Singleton #Component(modules = {AppModule.class})
public interface AppComponent
{
void inject (ApplicationClass applicationClass);
void inject (IntentService intentService);
void inject (Service service);
}
ApplicationClass
public class ApplicationClass extends Application
{
AppComponent appComponent;
#Override
public void onCreate()
{
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(new
Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread t, Throwable e) {
onUncaughtException(t, e);
}
});
appComponent = DaggerAppComponent
.builder()
.appModule(new AppModule(this))
.build();
appComponent.inject(this);
}
public AppComponent getAppComponent()
{
return this.appComponent;
}
private void onUncaughtException(Thread t, Throwable e)
{
e.printStackTrace();
Intent crash= new Intent(getApplicationContext(),Crash.class);
about.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(crash);
}
}
So I tried to inject the shared preferences in IntentService and I used these lines of code
inside the onCreate method of the my service (intentservice)
#Inject
SharedPreferences preferences;
#Override
public void onCreate()
{
super.onCreate();
((ApplicationClass)getApplication()).getAppComponent().inject(this);
}
But the problem is when I use this preferences variable in the onHandleIntent method, the application is crashing because the preferences is null..
So why it doesn't inject?
For anyone who encountered this problem.
As Vadim Korzun and EpicPandaForce mentioned in their comments above,
I should specify the specific class in the inject method.
So in my case my IntentService class was named GeofenceService
and inside the AppComponent interface I should write
void inject (GeofenceService service);
Same thing for Service
UPDATE:
So for all the people who have multiple Services that inherit from IntentService and want to save themselves from writing inject method for each Specific service.
I would suggest to do the steps below:
Create BasicIntentService that extends IntentService
In your AppComponent interface add the inject method which take as parameter you BasicIntentService.
In your BasicIntentSerive, you will have a protected SharedPrefrences variable annotated with the Inject annotation.
Still, in your BasicIntentService, inside the onCreate method you will call this line of code
((ApplicationClass)getApplication()).getAppComponent().inject(this);
Now each IntentService that you will create will extends the BasicIntentService and you will be able to use the SharedPreferences variable.
AppComponent:
#Singleton #Component(modules = {AppModule.class})
public interface AppComponent
{
void inject (YourApplicationClass applicationClass);
void inject (BasicIntentService intentService);
}
BasicIntentService
public class BasicIntentService extends IntentService
{
#Inject
protected SharedPreferences sharedPreferences;
#Override
public void onCreate()
{
super.onCreate()
((YourApplicationClass)getApplication()).getAppComponenet().inject(this);
}
}
SomeIntentService
public class SomeIntentService extends BasicIntentService
{
#Override
public void onCreate()
{
super.onCreate();
}
-----------
#Override
protected void onHandleIntent(#Nullable Intent intent)
{
// some code
if (sharedPreferences.contains(someKey))
{
// some code
}
else
{
// some code
}
}
}
i'm trying to update this below code to dagger2, but i get error for ObjectGraph:
import dagger.ObjectGraph;
public class App extends Application {
private static App instance;
private ObjectGraph objectGraph;
public App() {
instance = this;
}
#Override
public void onCreate() {
super.onCreate();
objectGraph = ObjectGraph.create(new AppModule());
}
public static void injectMembers(Object object) {
getInstance().objectGraph.inject(object);
}
public static <T>T get(Class<T> klass) {
return getInstance().objectGraph.get(klass);
}
public static App getInstance() {
return instance;
}
}
how can i update that to and which class must be use instead of ObjectGraph?
injectMembers used in this class
public class MyJobManager extends JobManager {
public MyJobManager(Context context) {
super(context, new Configuration.Builder(context)
.injector(new DependencyInjector() {
#Override
public void inject(BaseJob baseJob) {
App.injectMembers(baseJob);
}
})
.build());
}
}
now how can i inject with component?
my component:
#ActivitiesScope
#Component(dependencies = GithubApplicationComponent.class)
public interface ApplicationComponent {
void inject(ActivityRegister activityRegister);
void inject(ActivityStartUpApplication activityStartUpApplication);
void inject(GetLatestRepositories getLatestRepositories);
}
Dagger 2 doesn't use an ObjectGraph. It doesn't use anything as its replacement. Dagger1 did injection at runtime via reflection and used the ObjectGraph to provide that functionality. Dagger 2 does injection at compile time, thus it doesn't need a runtime object to represent the graph. Instead you'd want to build a component that links the modules you with to provide. You can then inject using that component.
See https://google.github.io/dagger/dagger-1-migration.html for more details.
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 the SomeAlarm the service context as a variable?
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.
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.
In Dagger 1 I had a base class setup such that it would handle creating a scoped graph and injecting dependencies into the current object. For example...
public abstract class MyBaseActivity extends Activity {
private ObjectGraph graph;
protected void onCreate(Bundle savedInstanceState) {
graph = ((MyApp) getApplication()).plus(getModules());
graph.inject(this);
}
protected Object[] getModules();
}
public class MyClass extends MyBaseActivity {
#Inject SomeDep someDep;
#Override
protected Object[] getModules() {
return new Object[/* Contains a module that provides SomeDep */];
}
}
This allowed for each subclass to supplement their own set of modules in addition to a standard application module.
After playing around with Dagger 2, it doesn't seem possible to handle a similar scenario...
public abstract class MyBaseActivity extends Activity {
private MyBaseActivityComponent component;
protected void onCreate(Bundle savedInstanceState) {
component = ((MyApp) getApplication()).component().plus(/* Can not accept an array */);
component.inject(this);
}
}
I worked around the above by modifying MyBaseActivityComponent such that it would list all possible modules it may use...
#Subcomponent(modules = {
Module1.class,
Module2.class
})
public interface MyBaseActivityComponent {
public void inject(MyBaseActivity activity);
}
So now I can do something like this...
public abstract class MyBaseActivity extends Activity {
private MyBaseActivityComponent component;
protected void onCreate(Bundle savedInstanceState) {
component = ((MyApp) getApplication()).component().plus(new Module1(), new Module2());
component.inject(this);
}
}
But now I have a problem where the injection will inject dependencies for MyBaseActivity but not it's subclasses. Suggestions?
Theoretically, you can do it like this.
1.) Specify a child scope
#Scope
#Retention(RUNTIME)
public #interface PerActivity {
}
2.) Specify the parent component
#Singleton
#Component(modules={Module1.class, Module2.class)
public interface MyApplicationComponent {
Dependency1 providesDependency1();
Dependency2 providesDependency2();
}
3.) Specify the child component
#PerActivity
#Component(dependencies={MyApplicationComponent.class}, modules={Module3.class})
public interface MyBaseActivityComponent extends MyApplicationComponent {
void inject(BaseActivity baseActivity);
Dependency3 providesDependency3();
}
4.) Create your module
#Module
public class Module3 {
#Provides
#PerActivity
public Dependency3 providesDependency3() {
return new Dependency3();
}
}
5.) Create Activity-level scoped component
public class BaseActivity extends AppCompatActivity {
private MyBaseActivityComponent baseComponent;
#Override
public void onCreate(Bundle saveState) {
super.onCreate(saveState);
baseComponent = DaggerBaseActivityComponent.builder()
.applicationComponent(((MyApp)getApplication()).component())
.build();
}
public MyBaseActivityComponent baseComponent() {
return baseComponent;
}
#Override
public void onDestroy() {
component = null;
super.onDestroy();
}
}
Please reply if it worked, previously I forgot to specify the dependencies in my Component and got compile errors, but it should work like this.
Also, if you need to specify a subcomponent for each Activity, then you can just specify the dependencies with provision methods in the BaseActivityComponent component...
#PerActivity
#Component(dependencies={MyBaseActivityComponent.class}, modules={Module4.class})
public interface MyActivityComponent extends MyBaseActivityComponent {
public void inject(MyActivity myActivity);
Dependency4 providesDependency4();
}
#Module
public class Module4 {
#PerActivity
#Provides
public Dependency4 providesDependency4(Dependency3 dependency3) {
return new Dependency4(dependency3);
}
}
public class MyActivity extends MyBaseActivity {
private MyActivityComponent component;
#Override
public void onCreate(Bundle saveInstanceState) {
super.onCreate(saveInstanceState);
component = DaggerMyActivityComponent.builder()
.applicationComponent(((MyApp)getApplication()).component())
.myBaseActivityComponent(baseComponent())
.build();
}
#Override
public void onDestroy() {
component = null;
super.onDestroy();
}
}
EDIT: #Subcomponent works to replace component dependencies with subcomponent factory methods according to the docs only if you use the following pattern (aka, embedding the subcomponent within the parent component using a provision/factory method definition):
#Singleton #Component
interface ApplicationComponent {
// component methods...
RequestComponent newRequestComponent(RequestModule requestModule);
}
Where
#Subcomponent(modules={RequestModule.class})
interface RequestComponent {
RequestSomething requestSomething();
}