Giannis Tsironis, this looks like the same issue that Mohamed Alouane posted in https://github.com/google/dagger/issues/899#issuecomment-337942596
So we are clear, this IllegalStateException
is not reproducible in any of the branches / tags in the companion Github project as it is without any modifications.
The Issue
Assuming that the issue you are having is the same as the issue I linked above, then the issue is that you are attempting to use @Provides
on a non-static instance method in your abstract AppModule
. Perhaps something like the following,
@Module(includes = AndroidInjectionModule.class)
abstract class AppModule { @Provides
Car car() {
return new Car();
}
}class Car {}
The above results in a crash at runtime,
Caused by: java.lang.IllegalStateException: AppModule must be set
The Fix
Making the method static will fix the issue,
@Module(includes = AndroidInjectionModule.class)
abstract class AppModule { @Provides
static Car car() {
return new Car();
}
}class Car {}
Keep reading for more details.
Diving Deeper
In order to provide dependencies in abstract modules, you must either use @Binds
on an abstract method or use @Provides
in a static method. This was not discussed in this article (though there were 2 places where I used @Provides
; [1], [2]) nor is it discussed in the official Dagger 2 user guide, which makes it a common pitfall. So I’ll discuss it here.
Let’s take a look at our Example1PresenterModule
,
@Module
public abstract class Example1PresenterModule { @Binds
@PerFragment
abstract Example1Presenter
example1Presenter(Example1PresenterImpl example1PresenterImpl);
}
This module is abstract. We are using the @Binds
annotation here on an abstract method to bind a concrete implementation (Example1PresenterImpl
) of the Example1Presenter
interface. This is equivalent to the following,
@Module
public abstract class Example1PresenterModule { @Provides
@PerFragment
static Example1Presenter
example1Presenter(Example1View view,
SingletonUtil singletonUtil,
PerActivityUtil perActivityUtil,
PerFragmentUtil perFragmentUtil) {
return new Example1PresenterImpl(view, singletonUtil,
perActivityUtil, perFragmentUtil);
}
}
In this case, we are using @Provides
on a static method to provide a concrete implementation (Example1PresenterImpl
) of the Example1Presenter
interface.
If we remove the static method modifier,
@Module
public abstract class Example1PresenterModule { @Provides
@PerFragment
Example1Presenter
example1Presenter(Example1View view,
SingletonUtil singletonUtil,
PerActivityUtil perActivityUtil,
PerFragmentUtil perFragmentUtil) {
return new Example1PresenterImpl(view, singletonUtil,
perActivityUtil, perFragmentUtil);
}
}
an IllegalStateException
will crash the application at runtime when attempting to access the example 1 activity,
Caused by: java.lang.IllegalStateException: Example1PresenterModule must be set
On a side note, a compile-time error (which is better than a crash at runtime) will occur if a @Module
contains both non-static @Provides
methods and abstract @Binds
or @Multibinds
declaration. For example,
@Module
public abstract class Example1PresenterModule { @Binds
@PerFragment
abstract Example1Presenter
example1Presenter(Example1PresenterImpl example1PresenterImpl); @Provides
Car car() {
return new Car();
}
}
When to use Binds vs Provides?
Using @Binds
saves us from having to write a lot of boilerplate object creation code. However, in some cases it is not possible to use @Binds
. For example, take a look at our BaseActivityModule
,
@Module
public abstract class BaseActivityModule {
...
@Provides
@Named(ACTIVITY_FRAGMENT_MANAGER)
@PerActivity
static FragmentManager
activityFragmentManager(Activity activity) {
return activity.getFragmentManager();
}
}
Here we need to provide a reference to the FragmentManager
. In order to get the Activity’s FragmentManager
, we must call its getFragmentManager()
method. Since abstract methods cannot have a body, we use @Provides
on a static method that takes in the activity and return activity.getFragmentManager()
in the body.
I will add a link to this discussion in the article to avoid future pitfalls / issues / confusion.