Dagger not initializing injected field in Android - android

Started introducing Dagger into my App and I'm having problems getting a very basic field initialized. Here's a reduced version of my code:
#Inject public DaggerUtils daggerUtils;
public class AppState extends Application {
#Override
public void onCreate() {
super.onCreate();
// Set up Dagger
AppModule appModule = new AppModule();
mObjectGraph.create(appModule);
daggerUtils.print();
}
}
Module used:
#Module(
injects = { AppState.class}
)
public class AppModule {
// This provides method is commented out because from what I can understand from the Dagger documentation
// Dagger should automatically take care of calling the constructor I have provided
// with the #Inject annotation. I have tried commenting this out as well and it still
// fails.
//#Provides
//DaggerUtils provideDaggerUtils() {
// return new DaggerUtils();
//}
}
Basic util class:
public class DaggerUtils {
#Inject
public DaggerUtils() {
}
public void print(){
Logger.e("Dagger", "printed instantiated");
}
}
So from what I understand because I have the #Inject annotation before the DaggerUtils constructor and the #Inject annotation before the DaggerUtils instance I'm using in my AppState class, Dagger should take care of initializing the DaggerUtils instance without me having to call the constructor. However it keeps giving me an NullPointerException when I try to call daggerUtils.print() (Line 12 in AppState class). Why is dagger not initializing DaggerUtils? I feel like I'm missing something very basic here. I've also tried using the #Provides method commented out in the AppModule to provide an instantiated DaggerUtils but it still isn't working.

I had same problem this evening.
For every class, who needs injection you must call:
mObjectGraph.create(appModule).inject(this);
That is usefull to create inject method in Application.
public void inject(Object object) {
mObjectGraph.inject(object);
}

Related

Can injecting a field member with Dagger be done with only a constructor

I inject a field member as follows:
#Inject
lateinit var repository: Repository
What I have noticed is that repository will only get set if I use a component builder:
init {
DaggerLoginViewModelComponent
.builder()
.build()
.inject(this)
}
But I have read in several places that the field member will get set even if you just mark the constructor of the class you want instantiated with Inject:
class Repository #Inject constructor() {
}
But I have not found this to be true. Even with the constructor having the Inject annotation present, I still need to run the builder. Can someone confirm whether this is true or not.
The way field injections work is through a supplemental method on the Dagger component, in this case inject(this).
If you look at the Dagger generated code, you'll see that inject() method's body contains the code to perform the member injection.
Here's how the generated code would look-
#Override
public void inject(Foo instance) {
injectFoo(instance);
}
private injectFoo(Foo instance) {
Foo_MembersInjector.injectRepository(instance, repositoryProvider.get());
return instance;
}
...
public final class Foo_MembersInjector implements MemberInjector<Foo> {
public static void injectRepository(Foo instance, Repository repository) {
instance.repository = repository // <-- this is where the actual injection happens
}
}
You're right when you say that Dagger knows how to construct the Repository object, but it doesn't know that this object has to be injected in a separate class. And that only happens when you call the inject() method with the instance of specific type, which is how it generates code to perform the injection.
Hope this helps.

how can I inject a dependency in a method?

I'm a beginner with dependency injection.. specifically Dagger 2. I'm trying to figure out if/how I can do something like this:
#Inject
public void someMethodName(int someInteger, SomeObject dependency){
// do something with the dependency.
}
Or do I need to put that dependency in as a class var? any help with this would be greatly appreciated. also in this case the variable someInteger is not a dependency, but is being added by the caller... does that matter?
can I call it like this:
this.someMethodName(5);
android studio does not like the above calling method (I'm assuming because I'm doing something wrong)
You need to create component which is annotated by #Component.
The Component accepts module which provides dependencies.
Every component's name that you create starts with Dagger prefix, e.g. for MyComponent.
Let's look at the following example:
#Singleton
#Component(modules = DemoApplicationModule.class)
public interface ApplicationComponent {
void inject(DemoApplication application);
}
We created ApplicationComponent with single injection method. What we're saying is that we want to inject certain dependencies in DemoApplication.
Moreover, in the #Component annotations we specify module with provision methods.
This is like our module looks like:
#Module
public class DemoApplicationModule {
private final Application application;
public DemoApplicationModule(Application application) {
this.application = application;
}
#Provides #Singleton SomeIntegerHandler provideIntegerHandler() {
return new MySomeIntegerHandlerImpl();
}
}
What we're saying by creating DemoApplicationModule is that the module can provide desired dependencies in the injection place specified by our Component.
public class DemoApplication extends Application {
private ApplicationComponent applicationComponent;
#Inject SomeIntegerHandler handler;
#Override public void onCreate() {
super.onCreate();
applicationComponent = DaggerApplicationComponent.builder()
.demoApplicationModule(new DemoApplicationModule(this))
.build();
applicationComponent.inject(this);
handler.someMethodName(5);
}
}
See documentation what you kind of dependencies you can obtain. Additionally to obtaining just raw instance you can obtain Provider, Factory or Lazy instance.
http://google.github.io/dagger/api/latest/dagger/Component.html
You can also create scoped dependencis, the lifecycles of which depend on the lifecycle of injection places, like Activities or Fragments.
Hope I gave you the basic notion of what Dagger is.
YOU CAN USE SOME INTERFACE
public interface myDependence{
int myFunction(int value);
}
NOW IMPLEMENT IN YOU CLASS
public myClass implements MyDependence{
#Override
int myFunction(int value){
// do something
}
}

Dagger2 - null instead of injected object

For making things simple, suppose I want to inject EmailValidator from apache validators into my activity:
public class MainActivity extends FragmentActivity {
#Inject
EmailValidator emailValidator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
I have a MainModule class:
#Module
public class MainModule {
#Provides
public EmailValidator providesEmailValidator() {
return EmailValidator.getInstance();
}
}
and MainComponent interface:
#Singleton
#Component(modules = MainModule.class)
public interface MainComponent {
EmailValidator getEmailValidator();
}
When trying to use my validator in activity, I'm getting a nullpointer exception:
java.lang.NullPointerException: Attempt to invoke virtual method 'boolean org.apache.commons.validator.routines.EmailValidator.isValid(java.lang.String)' on a null object reference
Obviously I'm missing something. I know that dagger creates component implementation for me. Should I use it? How?
If I do the following in my onCreate method:
emailValidator = Dagger_MainComponent.create().getEmailValidator();
then everything works fine.
But I want to be able to use #Inject annotation anywhere (probably on setter/constructor instead of a field) instead.
What am I missing?
I did something similar with dagger1 and it worked. Of course I needed to call ObjecGraph.inject(this) in activity. What's the dagger2 equivalent?
EDIT:
Ok, so I've found a solution. If anyone will ever have such a problem, there are some snippets:
1) I've created an application class:
public class EmailSenderApplication extends Application {
private MainComponent component;
#Override
public void onCreate() {
super.onCreate();
component = Dagger_MainComponent
.create();
component.inject(this);
}
public MainComponent component() {
return component;
}
}
2) In AndroidManifest.xml:
<application
android:name=".EmailSenderApplication"
...
3) And finally, in the activity class where I want to inject some components those two ugly as hell lines:
component = ((EmailSenderApplication) getApplication()).component();
component.inject(this);
Looks like you need to build your component as in:
component = Dagger_ MainComponent.builder()
.mainModule(new MainModule())
.build();
Typically, you do this in the onCreate method of your Application.
One good resource that may help you is the example apps in the Dagger 2 repo.
I also found this PR helpful, from a suggested update to Jake Wharton's u2020 sample app (from the main Dagger 2 Engineer). It gives a good overview of the changes you need to make when going from Dagger 1 to 2 and, apparently that's what he points people to as well.

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