What should go in the "injects" in a Dagger #Module? - android

Guice user, trying to understand a bit of the benefits of Dagger here.
Let's say I have the following
MyActivity.java
---------------
public class MyActivity {
#Inject MyImplicitClass myImplicitClass;
#Inject #Named("foo") MyExplicitClass myNamedExplicitClass;
...
}
MyImplicitClass.java
------------
public class MyImplicitClass {
#Inject
MyImplicitClass(MyExplicitClass myExplicitClass) {
...
}
...
}
MyModule.java
---------------
#Module(injects = { ? }) {
#Provides provideExplicitClass() {
return new MyExplicitClass();
}
#Named("foo") #Provides provideNamedExplicitClass() {
return new MyExplicitClass();
}
}
So, my question is, what should go in the Injects?
I know for a fact that MyActivity needs to go. Or rather, whatever "this" needs to have DaggerInjector.inject(this)
Does anything else?
Would Dagger the implicit construction injection class (MyImplicitClass) and/or the class explicitly provided in the module (MyExplicitClass) to also be specified?
MyExplicitClass wouldn't even make sense if I need it to be annotated.
However, the javadoc makes me feel I should error the side of inclusion
http://square.github.io/dagger/javadoc/dagger/Module.html#injects()

Dagger 1 does it's validation at compile therefore it needs all of the entry point you're going to use at runtime (objectgraph.get(entrypoint), objectgraph.inject(entrypoint)).
Entry points are the injectable classes which are at the top of the dependency graph. In Android most of the time those are your Activities, Fragments, Services, Broadcast Receivers. All compontents which are not created by Dagger. You would also list classes which are not part of any entry point's dependency tree again becoming an entry point of their own.
Those entry point are use to do validation by Dagger. Dagger will start validation at the entry points and tricle down the dependency tree and validate dependencies annotated with #Inject and #Provides from your Modules.
So in conclusion only entry points needs to be provided in the #Module(injects = { * })
In your example because the MyImplicitClass is an #Inject dependency of your entry point MyActivity you don't need to specify it in the #Modules(injects={}). The same is true for your MyExplicitClass dependency. Therefore from your example the only class that needs to be added to the list is in fact MyActivity.
Base on your example code, if you had something like this.
// MyIndependantClass.java
-----------------
public class MyIndependantClass {
#Inject
MyIndependantClass(MyExplicitClass myExplicitClass) {
}
}
// MyActivity.java
---------------
public class MyActivity {
#Inject MyImplicitClass myImplicitClass;
#Inject #Named("foo") MyExplicitClass myNamedExplicitClass;
...
protected void onCreate (Bundle savedInstanceState) {
MyIndependantClass myIndependantClass = MyObjectGraph.get(MyIndependantClass.class);
...
}
}
The fact that MyIndependantClass is created using ObjectGraph.get() and is not a direct dependency of your MyActivity entry point you would need to declare that class part of the injects list.
// MyModule.java
---------------
#Module(injects = { MyActivity.class, MyIndependantClass.class }) {
#Provides provideExplicitClass() {
return new MyExplicitClass();
}
#Named("foo") #Provides provideNamedExplicitClass() {
return new MyExplicitClass();
}
}

Related

Dagger2 dependency injection: How does it work in an android app?

I am trying to understand an example for an app with offline support using retrofit and room:
You can find the code for it here:
This project is using dependency injections with Dagger2. I've never worked with it so I am trying to understand how things work together. I understand the purpose of dependency injection but I don't understand the implementation of the project above.
I found a very good introduction into Dagger2 here:
A Friendly Introduction to Dagger 2
Dagger 2 example Code:
I worked through it and got most of it. Back to the actual project I am trying to understand (link 2). It still doesn't make sense to me and here is why:
The interface AppComponent has one method which is used:
public void inject(MainActivity2ViewModel viewModelModule); The return type is void. In the Dagger2 sample project (link 3 and 4) they use WeatherReporter getWeatherReporter(); which makes sense because later they call this method to get a WeatherReporter-Instance and Dagger2 manages all of the instantation process in the background. But I get nothing if the return type is void. Why is the return type not an object?
There is one #Inject in MainActivity2ViewModel:
#Inject
public void setRepository(GitHubRepository2 repository) {
this.repository = repository;
}
repository is the only field of MainActivity2ViewModel so it is a dependency. The GitHubRepository2 constructor has 3 parameters:
#Inject
public GitHubRepository2(GitHubApi api, GitHubDao dao, Executor executor)
For each of them there is a module explaining how to create those objects. But why is there an AppModule and a NetModule? Maybe the AppModule is there because DaoModule needs an Application reference but why is there a NetModule and where is it used?
There's a lot of comprehensive tutorials about Dagger2 in Android. But I'll show you a glimpse of what it's used for. And minimal usage.
Ultimately, dagger will use the annotation #Inject which will provide(reference to the object or value) to the variable.
Injection is usually used on reusable or boilerplate objects like Dao, Repository, ViewModel, NetworkAdapter
class SomethingThatRequiresNetwork { // Activity, Fragment
#Inject
MyReusableNetworkAdapter myReusableNetworkAdapter;
String baseUrl; // for example purpose only
SomeDependency someDependency;
void init() {
// #NOTE: DaggerMyExampleComponent is a generated class. It will be red before compilation.
MyExampleComponent MyExampleComponent = DaggerMyExampleComponent.builder().build();
MyExampleComponent.inject(this); // the actual injection happens here
}
// yes, you can just use #Inject on the variables directly but this is another use.
#Inject
void methodInjection(String baseUrl, SomeDependency someDependency) {
this.baseUrl = baseUrl;
this.someDependency = someDependency;
}
}
// ANSWER to the two questions
// this is a pseudocode of the generated code. You do not write this
// MyExampleComponent class
void inject(SomethingThatRequiresNetwork obj) {
// #NOTE: modules are actually instantiated by MyExampleComponent. Not called statically. I just shortened it
obj.myReusableNetworkAdapter = NetModule.provideNetworkAdapter();
obj.methodInjection(NetModule.provideBaseUrl(), SomeModule.provideSomeDependency());
}
// these here are modules that provide by return TYPE
// you write these
#Module
class NetModule {
#Provides
#Singleton
String provideBaseUrl() {
return "www.some-url.com";
}
#Provides
#Singleton // will store the object and reuse it.
// #NOTE: provision can work internally within modules or inter-module. the input here is provided by provideBaseUrl
MyReusableNetworkAdapter provideNetworkAdapter(String baseUrl) {
return new MyReusableNetworkAdapter(baseUrl);
}
}
#Modules
class SomeModule {
#Provides
#Singleton
SomeDependency provideSomeDependency() {
return new SomeDependency();
}
}
// Component. uses modules
#Singleton // .build() will reuse
#Component(modules = {NetModule.class, SomeModule.class})
interface MyExampleComponent {
// the method name doesn't matter
// the class type does matter though.
void inject(SomethingThatRequiresNetwork somethingThatRequiresNetwork);
// some other class that needs injection. #NOTE: I did not give example for this
void inject(SomethingThatRequiresDependency some);
}
NOTE. This code is usually written from bottom to top lol. You start writing the Component then Module then Injections.
Just follow the calls from the top of this answer and you'll figure out how Dagger2 works.

Dagger 2.2 component builder module method deprecated

I started using dagger 2.2 and the module methods in the Component builder are deprecated.
This is my Application component :
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(Application application);
}
And the Application module:
#Module
public class ApplicationModule {
Application application;
public ApplicationModule(Application application) {
this.application = application;
}
#Provides
#Singleton
Application providesApplication() {
return application;
}
}
Here is the generated class:
#Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerApplicationComponent implements ApplicationComponent {
private DaggerApplicationComponent(Builder builder) {
assert builder != null;
}
public static Builder builder() {
return new Builder();
}
public static ApplicationComponent create() {
return builder().build();
}
#Override
public void inject(Application application) {
MembersInjectors.<Application>noOp().injectMembers(application);
}
public static final class Builder {
private Builder() {}
public ApplicationComponent build() {
return new DaggerApplicationComponent(this);
}
/**
* #deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
*/
#Deprecated
public Builder applicationModule(ApplicationModule applicationModule) {
Preconditions.checkNotNull(applicationModule);
return this;
}
}
}
How do I initialize the component if not with the ComponentBuilder?
You should read the description of why it is deprecated. If you are using an IDE like IntelliJ or Android Studio you can just select the method and hit Control + Q on Windows to read the Javadoc including the deprecation notice.
The Javadoc reads:
#deprecated This module is declared, but an instance is not used in the component. This method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
And from this link you can see:
When the Dagger processor generates components, it only requires instances of modules and component dependencies that are explicitly needed to supply requests for a binding.
If all of a module’s methods that are used in the component are static, Dagger does not need an instance of that module at all. Dagger can invoke the static methods directly without a module.
If a module provides no bindings for a Component, no instance of that module is necessary to construct the graph.
It is safe to say that you can just ignore the deprecation. It is intended to notify you of unused methods and modules. As soon as you actually require / use Application somewhere in your subgraph the module is going to be needed, and the deprecation warning will go away.
It show deprecated because you are not using Component and module in your application by
#Inject
SomeObjectFromModule mSomeObject
if you are not injecting dependencies in your applications there is no use of initialising your component so dagger look for at least one usage
once you add these lines in any classes you want to inject views and then clean build and rebuild the project and your deprecation will be solved
It showing error when my Module have no #Provides method or the object that provide by Dagger is not used in app.
Example to remove deprecated module
Module
#Module
public class SecondActivityModule {
#Provides
Book provideBookTest() {
return new Book();
}
}
Activity
public class SecondActivity extends AppCompatActivity {
#Inject
Book test;
...
}
OR in Component
#Component(modules = SecondModule.class)
public interface SecondComponent {
void inject(SecondActivity activity);
Book getBookTest();
}
I have the same problem with host and I just want everyone has deprecated issue on Generated component builder class should check two things to save time:
1/ Correct dagger syntax for module, component also check carefully where you inject.
2/ Must have injection object (inject annotation and its object) in place you want to inject or else the dagger compiler cannot see where to use your module so some method will be deprecated.Just inject at least one module's provides to your injection place and re-compile the code, you won't have that issue anymore :)
you will get module method deprecated if you declare void inject(AppCompactActivity activity); in component class. instead of you have to use tight coupling like following void inject(MainActivity activity);and rebuild your project you will see, there is no deprecate method in module class

In Dagger are Singletons within the sub-graph cached or will they always be recreated when a new activity sub-graph is constructed?

I'm using Dagger to create activity specific object graphs. Within this subgraph, I make use of a Singleton MyPresentationModel.
When i exit my activity, and enter the activity again, my expectation is that a new instance of the activity specific object graph is created, which in turn would create a new instance of Singleton MyPresentationModel (by virtue of the #Singleton semantic per Dagger. See this So answer for specifics) which would then last for the life of the activity specific object graph.
However, this is not what i'm observing, every time the activity specific object graph is created, the same instance of MyPresentationModel is used. I added a debug point into the constructor of MyPresentationModel. The very first time we enter the constructor. Subsequently even on activity exits and reentries, we don't enter the constructor (and because of this the UserSession being used within my Presentation model uses the old value from the very first constructor injection).
While i can technically solve the problem by re-setting UserSession inside MyPresentaitonModel with an external public setter, I want to understand better the mechanics of the activity specific object graph creation/destruction.
By nullifying the graph in my onDestroy, does that still mean that there is a possibility of the Singletons within my subgraph being reused at a later point ? (possibly until they are truly GCed?)
Here's some code:
// MyAppModule
#Module(
includes = { UserSession.class},
injects = { MyApplication.class })
public class MyAppModule {
private final MyApplication _app;
MyAppModule(MyApplication app) {
_app = app;
}
// ...
}
// Main Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
_activityObjectGraph = MyApplication.get()
.getObjectGraph()
.plus(Arrays.<Object>asList(new SubModule()).toArray());
// Inject ourselves so subclasses will have dependencies fulfilled when this method returns.
_activityObjectGraph.inject(this);
}
#Override
protected void onDestroy() {
_activityObjectGraph = null;
// this eagerly allows GC, but doesn't necessarily destroy the subgraph ?
super.onDestroy();
}
// SubModule
#Module(injects = { MyPresentationModel.class, MainActivity.class },
addsTo = MyAppModule.class,
library = true)
public class SubModule {}
}
// MyPresentationModel
#Singleton
public class MyPresentationModel {
private UserSession _session;
#Inject
public MyPresentationModel(UserSession session) {
_session = session;
}
public void someMethodThatUsesSessionInfo() {
// _session.getUser() ...
}
}
#weefbellington posted a very informative answer, but reading it made me realize my question was not specific and clear enough. Here's attempt 2:
MyAppModule (main graph) -> provides a Singleton UserSession
MySubModule (sub graph plused onto MyAppModule) -> provides "activity specific" Singleton MyPresentationModel which requires a UserSession (provided my MyAppModule) on construction.
I now close the activity, destroying MySubModule (and also hopefully MyPresentationModel which is a Singleton), I update UserSession with some new information.
I open MainActivity again, thus re-creating the sub-graph from MySubModule, which inturn provides a MyPresentationModel.
The issue I'm noticing is that MyPresentationModel which is the local Singleton is not being reconstructed again i.e. this part of the code:
#Inject
public MyPresentationModel(UserSession session) {
_session = session;
}
is only ever being called once. My expectation was that this part of the code would be run again, and the UserSession would be pulled again from the Main graph and since it was updated, it would hold the updated values. My question is: are Singletons within the sub-graph cached in anyway or will they always be recreated when a new activity sub-graph is spawned?
How MyPresentationModule is injected depends on how your modules are specified. For example, assume that you are injecting the class Foo:
public class Foo {
private final MyPresentationModel model;
#Inject
public Foo(MyPresentationModel model) {
this.model = model;
}
}
If your modules are structured like (A), then the MyPresentationModel singleton will be injected into Foo by the main object graph:
EXAMPLE A
#Module(injects = { Foo.class })
public class MainModule { ... }
#Module(addsTo = MainModule.class, injects = { MyPresentationModel.class })
public class SubModule { ...}
Alternatively, if your modules are structured like (B), then the MyPresentationModel singleton will be injected into Foo by the subgraph:
EXAMPLE B
#Module
public class MainModule { ... }
#Module(addsTo = MainModule.class, injects = { Foo.class, MyPresentationModel.class })
public class SubModule { ... }
In your particular case, since you have specified that MyAppModule injects MyApplication, I would guess that you are trying to inject MyPresentationModel into your Application class. This is probably not what you want to do. You probably want inject this into your Activity class using the submodule, as in (C).
EXAMPLE C
#Module(injects = { MainActivity.class, MyPresentationModel.class },
addsTo = MyAppModule.class,
library = true)
public class SubModule { ... }
public class MainActivity {
#Inject MyPresentationModel presentationModel;
...
}
If you do this the MyPresentationModel singleton will be bound to the Activity subgraph instead of the main graph, and should be disposed when the Activity is destroyed.
Once you have a handle on Dagger, you might want to check out Mortar, which gives you finer-grained control over creation and destruction of ObjectGraph subscopes.

What does #Module means in dagger for android?

I have read many blogs but still i am not able to figure out #Module annotation functioning in dagger.
#Inject i got that it provides dependency injection at runtime. But what does #Module does.
since the object graph is also built on module.
For ex i.e i have this snippet of code from https://github.com/AndroidBootstrap/android-bootstrap.
#Module(
complete = false,
injects = {
BootstrapApplication.class,
BootstrapAuthenticatorActivity.class,
MainActivity.class,
BootstrapTimerActivity.class,
}
)
public class BootstrapModule {
}
so what does it basically does. since i am also trying to build one application using dagger as dependency injection for android.But since I am not able to get #Module concept clearly I am just stuck.
Can anyone please help me out with some basic example or concept. I think this will be helpful for all who is using dagger.
If you have a look to the docs for the annotation, a #Module annotated class defines a class that contributes to the dagger object graph. In the Spring framework for example, the equivalent would be the #Configuration anntotation. It defines a configuration point for your object graph, where you declare which objects you want to be available for injection and their scopes.
As a simple example, let's say we want a singleton object to be used by any Activity in the app. It has to be created in the module:
#dagger.Module(injects = {MyActivity.class})
public class Module {
#Provides
#Singleton
public MySinletonBean provideMySingleton() {
return new MySinletonBean();
}
}
This will create a MySingleton object which can be injected in MyActivity. This is a very basic example, but we can perform other actions in the graph there, like using dependencies in the constructors:
#dagger.Module(injects = {MyActivity.class})
public class Module {
private DependencyBean dependency = new DependencyBean();
#Provides
#Singleton
public MySinletonBean provideMySingleton() {
return new MySinletonBean(dependency);
}
#Provides
#Singleton
public MySinletonBean provideMyOtherSingleton() {
return new MyOtherSinletonBean(dependency);
}
}
Then, in MyActivity we need to access the graph for the application in the onCreate method:
#Inject
MySingletonBean singleton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_activity);
((MyApplication) getApplication()).getGraph().inject(this);
}
So, who does create the object graph here? The MyApplication class does it when your application starts (don't forger to add it in your androidManifest.xml):
public class MyApplication extends Application {
private ObjectGraph graph;
public ObjectGraph getGraph() {
return graph;
}
#Override
public void onCreate() {
super.onCreate();
graph = ObjectGraph.create(new Module(this));
graph.inject(this);
}
}
So the execution flow in a dagger app would be:
The android app starts and the MyApplication class builds the graph, parsing the #Module annotated classes and keeping an instance of it.
Then, the classes declared in the module can access its objects just injecting themselves in the object graph. Gradle then will evaluate their #Inject annotations and perform the dependency injections.
I guess Annotation Processing Tool requires that to generate code at the compile time.
This makes it Dagger can provide validation at compile time and not only at runtime.

Dagger not injecting Android Annotations class

Alright, I'm having an issue trying to mix frameworks.
So, I have a #SharedPref annotated class that should generate a Shared Preferences manager from Android Annotations. The class looks a bit something like this:
DownloadPrefs.java
#SharedPref(value= SharedPref.Scope.UNIQUE)
public interface DownloadPrefs {
#DefaultBoolean(false)
boolean hasEnabledDownload();
#DefaultBoolean(false)
boolean showedDownloadDialog();
#DefaultLong(0)
long downloadRefreshedOn();
}
Now, I'd like to inject the resulting class (which will be DownloadPrefs_) into a Fragment to make use of it. The fragment has had working injection before adding the new module, so I'm only going to write here what I added:
Fragment.java
#Inject DownloadPrefs_ downloadPrefs;
Now, since the actual DownloadPrefs_ class is generated at runtime, it would make the most sense to create an #Provides annotation for it, since I can't mark a constructor as injected. Nor does the DownloadPrefs_ have a no-arg constructor. The module I'm using then receives the new #Provides:
DownloaderModule.java
#Provides //#Singleton // Does not work with/out #Singleton
DownloadPrefs_ provideDownloadPrefs() {
return new DownloadPrefs_(MinimalBible.getApplication());
}
To be technical about it, the DownloadPrefs_ constructor that gets generated by Android Annotations expects a Context passed to it, I would have guessed that the Application context would be suitable. Otherwise, I'm not sure how I could possibly get access to the Activity context. Or whether that would actually break the ObjectGraph.
However, when I go to run the actual injection, I get the following message:
Caused by: java.lang.IllegalStateException: Errors creating object graph:
org.bspeice.minimalbible.activities.downloader.DownloadPrefs_ has no injectable members. Do you want to add an injectable constructor? required by class org.bspeice.minimalbible.activities.downloader.BookListFragment
Any clue on what's going on? It doesn't seem like the questions asking about "no injectable members" on other SO questions answered my case. I had a working app before adding the code above.
UPDATE: After doing some double-checking, I came across the following weird behavior. If I copy out the pre-built Android Annotations class, rename it, and inject that, everything works. Additionally, I can verify that the original built Android Annotations class (the DownloadPrefs_.java) does in fact exist in the .dex, so Dagger should have no reason to not be able to find it. Everything is doing a debug build, so I can't imagine ProGuard is messing anything up.
At this point, I'm going to create a minimal project to demonstrate the error, and file an issue with Dagger. In the mean time, just need to rewrite the Prefs class until I can get this sorted out.
UPDATE 5/12/2014
Here are the modules responsible for injection:
MinimalBibleModules.java
#Module(
injects = {
MinimalBible.class
},
includes = {
ActivityModules.class
}
)
public class MinimalBibleModules {
}
ActivityModules.java
#Module(
includes = {
ActivityDownloaderModule.class
}
)
public class ActivityModules {
}
ActivityDownloaderModule.java
#Module(
injects = {
BookListFragment.class,
DownloadManager.class,
BookRefreshTask.class
}
)
public class ActivityDownloaderModule {
#Provides #Singleton
DownloadManager provideDownloadManager() {
return new DownloadManager();
}
#Provides
EventBus provideBus() {
return new EventBus();
}
#Provides //#Singleton
DownloadPrefs_ provideDownloadPrefs() {
return new DownloadPrefs_(MinimalBible.getApplication());
}
}
Also, how the graph gets created:
MinimalBible.java
public class MinimalBible extends Application {
private ObjectGraph graph;
private static MinimalBible instance;
public MinimalBible() {
instance = this;
}
#Override
public void onCreate() {
graph = ObjectGraph.create(new MinimalBibleModules());
graph.inject(this);
}
There are two parts here. First, how you get access to the Context. You can do static things as you are, though that's not advisable. Generally, you should configure your graph with a stateful module that carries the context, like this:
#Module
class ApplicationModule {
private final Application application;
public ApplicationModule(Application app) {
this.application = app;
}
// you can mark this singleton, but it's minor overhead
// and the fact that you have a single instance stored
// means it's semantically equivalent. But for clarity
// it's sometimes good to make the point.
#Provides
#Singleton
Application application() {
return application;
}
// optionally: bind it as a Context with a qualifier.
// note: never bind Context without a qualifier annotation
// as Activity and Application are both Context subtypes.
#Provides
#Singleton
#PerApplication
Context appContext(Application app) {
// Doing this instead of returning this.application is
// semantically equivalent but links #PerApplication Context
// to Application, so in graph analysis and error reporting
// the link is clearer. That's a personal choice.
return app;
}
}
At any rate, you then when you create the graph:
Application appInstance = ...;
ObjectGraph appGraph = ObjectGraph.create(
MyAppModule.class,
new ApplicationModule(appInstance));
The Application is then seeded into the graph and can be depended-upon by other types that declare it as a dependency.

Categories

Resources