I'm new to Dagger and at the begininig I face some issues. I have simple structure so far in my project. My injection module:
#Module(
injects = {GameBoardFragment.class, GameManager.class},
complete = false,
library = true
)
public class GameObjectsProviderModule {
private final Application mApplication;
public GameObjectsProviderModule(Application application){
this.mApplication = application;
}
#Provides
#Singleton
public GameManager provideGameManager(){
return new GameManager();
}
#Provides
public Board getBoard(){
return new Board();
}
#Provides #Singleton #ForApplication Context provideAppContext() {
return mApplication;
}
My simplified custom app class looks like that:
public class MyApp extends Application {
private static ObjectGraph mApplicationGraph;
#Override public void onCreate() {
super.onCreate();
mApplicationGraph = ObjectGraph.create(new GameObjectsProviderModule(this));
}
public static ObjectGraph getObjectGraph(){
return mApplicationGraph;
}
}
And now, my fragment looks like that:
public class GameBoardFragment extends Fragment {
#Inject
GameManager mGameManager;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
MyApp.getObjectGraph().inject(this);
View root = inflater.inflate(R.layout.fragment_game_board, container, false);
findViews(root);
confViews();
return root;
}
}
And finally my GameManager class
public class GameManager {
#Inject Board mBoard;
public GameManager(){
MyApp.getObjectGraph().inject(this);
}
}
Andy hey, it works! Great. But my question is why it doesn't work in case I comment out this line:
MyApp.getObjectGraph().inject(this);
Do we have always explicitly call inject() function to make all necessary injections take place event in nested objects?
It looks not, as shows coffe maker example:
https://github.com/square/dagger/tree/master/examples/simple/src/main/java/coffee
Why then I have to call inject() in GameManager class to get it working?
Edit:
The consturctor injection approach works just fine.
But for future use I tried to get field injection running, and so far I haven't succeed.
I commented out both #Provide methods from module and I made my GameManager look like this:
#Singleton
public class GameManager {
#Inject Board mBoard;
#Inject
public GameManager(){
}
}
and Board:
public class Board {
#Inject
public Board() {
}
}
However mBoard doesn't get instantiated. I will try more and I suppose I figure out the proper solution.
You should rather use constructor injection (like for example the Thermosiphon does), and avoid field injection unless necessary. For example, let your GameManager have the Board as a constructor argument:
#Singleton
public class GameManager {
private final Board mBoard;
#Inject
public GameManager(final Board board){
mBoard = board;
}
}
Dagger will use this constructor to create an instance of the GameManager (hence the #Inject annotation), and notice it needs a Board instance. Using the ObjectGraph, it will create a Board first, and use that instance to create the GameManager. You can remove the #Provides GameManager method if you do it this way.
In your case, you have a #Provides Board method in your module. If you add an #Inject annotation to your Board constructor, you can remove this provides-method from your module:
public class Board {
#Inject
public Board() {
}
}
If you don't want to use constructor injection, the problem is that you told Dagger that you want to create your GameManager instance yourself (because you have the #Provides GameManager method). If you remove this method, and let Dagger create it for you like above but without the Board parameter in the constructor, Dagger will also notice the #Inject Board field and inject that as well.
A final remark. Remove the library = true and complete = false statements! These are not necessary at all in this example. Only add them if you really know what you're doing. By not having them, Dagger will create compile-time errors to notify you that something is wrong. If you do include them, you're telling Dagger "Hey, I know what I'm doing, don't worry, it's all correct", when in fact it isn't.
Edit
A quote from the Dagger1 site:
If your class has #Inject-annotated fields but no #Inject-annotated
constructor, Dagger will use a no-argument constructor if it exists.
Classes that lack #Inject annotations cannot be constructed by Dagger.
I do not use this method very often, so I could be wrong. I think this means that you should remove the #Inject annotation from your constructor, like so:
#Singleton
public class GameManager {
#Inject Board mBoard;
public GameManager(){ // Or remove the constructor entirely since it's empty
}
}
Since there is an #Inject annotation on the Board field, Dagger will know to use the no-argument constructor.
I was struggling with the same issue as most of the dagger examples everywhere use a Module with Provides and I had a hard time finding a complete example that just does not use Provides.
I created this one. It uses field injection (not constructor injection) and works just fine through the hierarchy without requiring any call to inject. I am using Dagger 1.2.2.
Main.java
import javax.inject.*;
import dagger.*;
import dagger.ObjectGraph;
public class Main {
public static void main(String[] args) {
ObjectGraph objectGraph = ObjectGraph.create(new CarModule());
Car car = objectGraph.get(Car.class);
car.start();
}
}
CarModule.Java
import dagger.Module;
#Module(injects = Car.class)
public class CarModule {
}
Car.Java
import javax.inject.*;
public class Car {
#Inject public Engine engine;
#Inject Car() {
System.out.println("Car constructor");
}
public void start() {
engine.start();
}
}
Engine.Java
import javax.inject.*;
public class Engine {
#Inject WaterPump waterPump;
Engine() {
System.out.println("Engine Constructor");
}
void start() {
waterPump.run();
System.out.println("starting engine.");
}
}
WaterPump.Java
import javax.inject.*;
public class WaterPump {
#Inject WaterPump() {
System.out.println("WaterPump Constructor.");
}
public void run() {
System.out.println("WaterPump running.");
}
}
The output is:
Car constructor
Engine Constructor
WaterPump Constructor.
WaterPump running.
starting engine.
Without The CarModule that declares it injects Car.Class this does not work. You get:
Exception in thread "main" java.lang.IllegalArgumentException: No
inject registered for members/Car. You must explicitly add it to the
'injects' option in one of your modules.
But notice that CarModule does not #Provides anything. It is dagger that automatically creates all the dependencies using the object graph.
Also note that you don't have to place an #Inject annotation on the default constructor if you have a #Inject field in the class. For Car class I used it on both the constructor and the field and in Engine class I used it just for the field and not for the constructor and it works fine as documented.
Related
I think I'm missing something. I get this error:
PostsVM cannot be provided without an #Inject constructor or from an
#Provides-annotated method.
Assume classes as follows :
#Module
public class AppModule {
private final Application mApplication;
#Singleton
#Provides
ViewModel provideListViewModel() {
return new PostsVM();
}
}
And a class PostVM
#Singleton
public class PostsVM extends ViewModel {
public boolean get(){
return true;
}
}
And a component :
#Singleton
#Component(modules = AppModule.class)
public interface AppComponent {
void inject(Global global);
void inject(MainActivity mainActivity);
#Architecture.ApplicationContext
Context getContext();
Application getApplication();
}
And in activity :
#Inject
public ViewModelProvider.Factory factory;
#Override
protected void onCreate(Bundle savedInstanceState) {
InjectorClass.inject(this);
As you can see, the example given for PostVM class, does't depend on anything, why do I need an #inject constructor in it?
tl;dr To prevent errors and to follow convention.
From the JavaDoc of #Inject you can read:
Injectable constructors are annotated with #Inject and accept zero or more dependencies as arguments. #Inject can apply to at most one constructor per class.
And it's always good practice to follow the convention / documentation.
So #Inject marks an entry point for Dagger to signal it how and where to create your class. It is a clear sign of how you intend your class to be used.
What if you have multiple constructors?
What if you require additional setup and should use a #Module instead?
By just defaulting to a no-args constructor (if possible) things could start breaking very easily and you might not be able to pinpoint the source easily if you just assume Dagger does its job.
__ cannot be provided without an #Inject constructor or from an #Provides-annotated method.
This error on the other hand gives you a strong signal that you're missing something and cannot be ignored.
I'm studying Dagger 2 so I would like to understand some basic things. I have the following code:
#Module
public class MainModule {
#Provides
public Presenter provideMainActivityPresenter(Model model){
return new MainPresenter(model);
}
#Provides
public Model provideMainModel(){
return new MainModel();
}
}
and my MainPresenter class looks like this:
public class MainPresenter implements Presenter {
#Nullable
private ViewImpl view;
private Model model;
public MainPresenter(Model model) {
this.model = model;
}
#Override
public void setView(ViewImpl view) {
this.view = view;
}
}
Instead of the above code, could I do the following?
public class MainPresenter implements Presenter {
#Nullable
private ViewImpl view;
#Inject
Model model;
#Override
public void setView(ViewImpl view) {
this.view = view;
}
}
Because the MainPresenter depends on the Model and it is not #Nullable.
Or this is wrong?
I don't understand when I should put a dependency as a constructor argument, or when I should use #Inject
You have basically 3 ways to use Dagger
Constructor injection
Field injection
Providing it from a module yourself
(There is also method injection which calls a method after creating your object)
The following is using a module that provides your class. While not wrong, this is the most overhead to write and maintain. You create the object by passing in the requested dependencies and return it:
// in a module
#Provides
public Presenter provideMainActivityPresenter(Model model){
// you request model and pass it to the constructor yourself
return new MainPresenter(model);
}
This should be used with things that require additional setup, like Gson, OkHttp, or Retrofit so that you can create the object in one place with the required dependencies.
The following would be used to inject objects where you don't have access or don't want to use the constructo. You annotate the field and register a method at the component to inject your object:
#Component class SomeComponent {
void injectPresenter(MainPresenter presenter);
}
public class MainPresenter implements Presenter {
// it's not annotated by #Inject, so it will be ignored
#Nullable
private ViewImpl view;
// will be field injected by calling Component.injectPresenter(presenter)
#Inject
Model model;
// other methods, etc
}
This will also provide you with overhead to register all your classes at a presenter and should be used when you can't use the constructor, like Activities, Fragments, or with Services. That's why all those Dagger samples have those onCreate() { DaggerComponent.inject(this); } methods to inject parts of the Android framework.
Most importantly you can use Constructor Injection. You annotate the constructor with #Inject and let Dagger find out how to create it.
public class MainPresenter implements Presenter {
// not assigned by constructor
#Nullable
private ViewImpl view;
// assigned in the constructor which gets called by dagger and the dependency is passed in
private Model model;
// dagger will call the constructor and pass in the Model
#Inject
public MainPresenter(Model model) {
this.model = model;
}
}
This only requires you to annotated your class constructor and Dagger will know how to handle it, given that all the dependencies (constructor arguments, Model in this example) can be provided.
All of the methods mentioned above will create an object and can / should be used in different circumstances.
All of those methods either pass the dependencies to the constructor, or inject #Inject annotated fields directly. Dependencies should thuse be in the constructor or annotated by #Inject so that Dagger knows about them.
I also wrote a blog post about the basic usage of Dagger 2 with some further details.
I'm having a similar problem like the one in this question.
While the accepted answer does help, but I'm missing final piece to solve the problem.
I have 2 android library modules: common and exp which depends on common.
Everything under common:
#Module
public class CommonModule {
#Singleton
#Provides
public Repository providesRepository() {
return new Repository();
}
}
#Singleton
#Component(modules={CommonModule.class})
public interface CommonComponent {
void inject(CommonClass commonClass);
/**
CommonClass needs instance of Repository
**/
}
public class CommonDIHolder {
public static CommonComponent sComponent;
public static void init() {
sComponent = DaggerCommonComponent.builder().build();
}
}
Everything under exp:
#Module(includes={CommonModule.class})
public class ExpModule {
#Singleton
#Provides
public ExpResource provideExpResource() {
return new ExpResource();
}
}
#Singleton
#Component(modules={ExpModule.class}, dependencies={CommonComponent.class})
public interface ExpComponent {
void inject(ExpClass expClass);
/**
ExpClass needs instance of Repository and ExpResource
**/
}
public class ExpDIHolder {
public static ExpComponent sComponent;
public static void init() {
sComponent = DaggerExpComponent.builder()
.commonComponent(CommonDIHolder.sComponent)
.build();
}
}
I need both CommonClass and ExpClass receive the same instance of Repository.
The problem with this approach is that #Singleton can't depends on #Singleton. So I have to change the scope of ExpComponent into self-defined scope called #ExpScope. Then I changed the provideExpResource into #ExpScope as well.
Then I encountered an error saying that ExpComponent may not reference bindings with different scopes. It refers to the provideRepository which has different scope (#Singleton) on it. If I changed the scope into ExpScope then the CommonComponent will have different scope with provideRepository.
If I changed all #Singleton into #ExpScope then I receive this error message: depends on scoped components in a non-hierarchical scope ordering
What should I do? Or I'm doing the wrong approach here?
Use one and only one #Singleton scoped component
You should have one and only one #Singleton scoped component like this:
#Singleton
#Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
}
Only specify Activities, Fragments, and Services as explicit injection targets for Components
In an Android app, you should only list Activities, Fragments and Services as injection sites. You should configure Dagger 2 to inject the rest of your dependencies without having to resort to calling component.inject(this) inside them.
For example, if your CommonClass looks like this:
public class CommonClass {
#Inject Repository repository;
public class CommonClass() {
CommonComponentHolder.get().inject(this);
}
}
Refactor it like this:
public class CommonClass {
private final Repository repository;
#Inject
public class CommonClass(Repository repository) {
this.repository = repository;
}
}
Now when you have an Activity or Fragment that needs CommonClass and you are injecting with CommonComponent or one of its sub-components or dependent components, they can obtain instances of CommonClass wired with the correct dependencies:
public class MyActivity extends AppCompatActivity {
#Inject CommonClass commonClass;
public void onCreate(Bundle savedInstanceState) {
CommonComponentHolder.getComponent().inject(this);
}
}
Use subcomponents or dependent components to specify the injection targets
Now you have a #Singleton scoped component, you'll probably want to create a component for a narrower scope for your Activity or Fragment. You'll have to connect it to your CommonComponent, so use dependent components or subcomponents (subcomponents are preferred as of Dagger 2.10). Since you say you have already tried defining a #ExpScope, I think the missing piece is to make subcomponent or dependent component with the #ExpScope that injects your Activity or Fragment.
Something like the following for the top-level singleton component:
#Singleton
#Component(modules={CommonModule.class, ExpModule.class})
public interface CommonComponent {
ExpComponent.Builder exComponent();
}
And then for the subcomponent:
#ExpScope
#Subcomponent(modules = {NarrowerScopedModule.class})
public interface ExpComponent {
#Subcomponent.Builder
public interface Builder {
Builder narrowerScopedModule(NarrowerScopedModule narrowerScopedModule);
ExpComponent build();
}
}
There are good working examples of Android projects in the Google Android Architecture Blueprints Github repo
I have singleton class that 2 other classes depend on: another singleton and a service. The problem is that in practice each of them receives a different instance of what's supposed to be a singleton. I'm trying to figure out why. Here's the gist of it:
The singleton dependency class:
#Singleton
public class SingletonDependency {
#Inject
public SingletonDependency() {
// ...
}
}
The other singleton which depends on it:
#Singleton
public class DependentClass {
#Inject
public DependentClass(SingletonDependency singletonDependency) {
// ...
}
}
The service which depends on it:
public class DependentService extends Service {
#Inject SingletonDependency mSingletonDependency;
#Override
public void onCreate() {
CoreInjector.INSTANCE.getCoreComponent().inject(this);
}
}
I do not provide SingletonDependency explicitly since it has a #Inject constructor and Dagger2 takes care of it for me. Is this the root of it?
Edit:
Here's my injector:
public enum CoreInjector {
INSTANCE;
private CoreComponent mCoreComponent;
public void init(Context context) { // called by the Application's onCreate()
mCoreComponent = DaggerCoreComponent.builder()
.coreModule(new CoreModule(context))
.build();
}
public CoreComponent getCoreComponent() {
return mCoreComponent;
}
}
The Component itself:
#Singleton
#Component(modules = {CoreModule.class})
public interface CoreComponent {
void inject(DependentService dependentService);
}
The Module itself doesn't provide the dependency explicitly, but once I do, everything works as expected - same instance.
Edit 2
Conclusions posted as an answer.
I figured it out. My singleton class implements an interface, which is what my dependent classes depends on - not the implementation. I guess Dagger2 can't make that leap even though the implementation has a injected constructor.
Explicit #Provides method in a module was the only way to go.
Another possible cause of a singleton created many times is that #Singleton is enforced only by #Component. If a singleton is called by another #Component (or another instance of the same component), it will be re-created.
I am "Daggering" my Android app and I am facing a little problem that I don't know if it's me or framework's fault. If it's me I will be very disappointed by myself :)
I have the following class to provide:
#Singleton
public class XmlService {
private final DataCommitter<XmlWritable> mXmlCommitter;
private final DataReader<XmlPushable> mXmlReader;
private final ConcurrentObjectMonitor mConcObjMonitor;
#Inject
public XmlService(DataCommitter<XmlWritable> xmlCommitter,
DataReader<XmlPushable> xmlProvider,
ConcurrentObjectMonitor concObjMonitor) {
mXmlCommitter = xmlCommitter;
mXmlReader = xmlProvider;
mConcObjMonitor = concObjMonitor;
}
With the following (among the others) class:
public class XmlDataReader implements DataReader<XmlPushable> {
// No Singleton no more.
// Eager Singleton (Therefore it should be made thread safe)
//static XmlDataReader mInstance = new XmlDataReader();
[CUT]
protected XmlPullParser mXmlPullParser;
#Inject
public void XmlDataRead(XmlPullParser xmlPullParser) {
mXmlPullParser = xmlPullParser;
}
This class is referred in my XmlServiceModule like this:
#Module(complete = true)
public class XmlServiceModule {
#Provides DataReader<XmlPushable> provideDataReader(XmlDataReader dataReader) {
return dataReader;
}
}
Now, the question is, is it legal to Inject provided classes? Because I am getting an error with the #Inject on the XmlDataReader ctor: Cannot inject public void XmlDataRead(org.xmlpull.v1.XmlPullParser).
EDIT: sorry guys, there was an error in my sample code, but I will leave it as is, because it can be useful in order to understand Christian's answer below.
Actually, you have an error in your sample code. You have no injectable constructor - you cannot inject an instance method, only a constructor, and that method is never called.
You should have:
public class XmlDataReader implements DataReader<XmlPushable> {
protected final XmlPullParser mXmlPullParser;
#Inject
public XmlDataReader(XmlPullParser xmlPullParser) {
mXmlPullParser = xmlPullParser;
}
}
This way it's a constructor, and will be properly injected.
As to the overall approach, you're in the right direction. You #Provide DataReader<XmlPushable, and effectively bind XmlDataReader to it in your provides method. So far so good. Dagger, when asked for DataReader<XmlPushable> will use that binding, and will effectively pass-through the dependency and provide XmlDataReader to satisfy this.
XmlDataReader has an #Inject annotated constructor, so Dagger's analysis will see it as an "injectable type" so you don't need an #Provides to provide it. As long as you either have an XmlPullParser that either has an #Inject annotated constructor or is provided in an #Provides method on a module, what you've coded here seems good, but is not quite complete.
You don't have any entryPoints listed in your #Module, and you must have a class that will be the first thing you obtain from the ObjectGraph. So this code is reasonable as far as it goes, but incomplete. You need something that injects (through a field or constructor) DataReader<XmlPushable> For example, you might make a FooActivity which does this.
Consider:
public class XmlDataReader implements DataReader<XmlPushable> {
protected XmlPullParser mXmlPullParser;
#Inject public XmlDataReader(XmlPullParser xmlPullParser) {
mXmlPullParser = xmlPullParser;
}
}
#Module(entryPoints = { FooActivity.class, BarActivity.class })
public class XmlServiceModule {
#Provides DataReader<XmlPushable> provideDataReader(XmlDataReader dataReader) {
return dataReader;
}
#Singleton
#Provides XmlPullParserFactory parserFactory() {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
return factory;
}
#Provides XmlPullParser parser(XmlPullParserFactory factory) {
XmlPullParser xpp = factory.newPullParser();
}
}
public class YourApp extends Application {
private ObjectGraph graph;
#Override public void onCreate() {
super.onCreate();
graph = ObjectGraph.get(new ExampleModule(this));
}
public ObjectGraph graph() {
return objectGraph;
}
}
public abstract class BaseActivity extends Activity {
#Override protected void onCreate(Bundle state) {
super.onCreate(state);
((YourApp) getApplication()).objectGraph().inject(this);
}
}
class FooActivity extends BaseActivity {
#Inject DataReader<XmlPushable> reader;
#Override public void onCreate(Bundle bundle) {
super.onCreate(bundle);
// custom Foo setup
}
}
class BarActivity extends BaseActivity {
#Inject DataReader<XmlPushable> reader;
#Override public void onCreate(Bundle bundle) {
super.onCreate(bundle);
// custom Bar setup
}
}
This is probably close to what you want. All things are reachable from an entry point, and all things you depend on are bound. The two Activities are your "entry points" (roots in the object graph). When they are initialized, they ultimately call the ObjectGraph's inject(Object) method on themselves, which causes Dagger to inject any #Inject annotated fields. Those fields are the DataReader<XmlPushable> fields, which is satisfy by XmlDataReader, which is provided with an XmlPullParser, which is provided by using a XmlPullParser. It all flows down the dependency chain.
Small note - #Module(complete=true) is the default. You don't need to specify complete, unless it's incomplete and you specify false