0
votes

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?

1
You don't have to inject context and shared preferences to IntentService, IntentService has already inherited from Context. Your problem is that you should use name on target class (in inject method) in AppComponent for examle: void inject (ApplicationClass applicationClass); void inject (CustomIntentService intentService); void inject (SimpleIntentService service); - Onregs
You need to specify a specific concrete class and not its parent class to inject in it. So you can't just say IntentService and inject into any intent service, it will be null because your class is not IntentService, it is WhateverService. - EpicPandaForce
@VadimKorzun thanks as you can see I meant shared preferences and edited my question. Thanks for your clarify about my problem - Elior
@EpicPandaForce thank you also ! I thought that if I passing to the inject method the IntentService as parameter I could use this function for all the classes in my app that are inherit from IntentService. Thanks :) - Elior

1 Answers

2
votes

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:

  1. Create BasicIntentService that extends IntentService
  2. In your AppComponent interface add the inject method which take as parameter you BasicIntentService.
  3. In your BasicIntentSerive, you will have a protected SharedPrefrences variable annotated with the Inject annotation.
  4. Still, in your BasicIntentService, inside the onCreate method you will call this line of code

    ((ApplicationClass)getApplication()).getAppComponent().inject(this);

  5. 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
     }
   }

}