I am playing with Dagger on Android. I created a model UserPreference
, a module called PreferenceModule
and another class UserPreferenceTest
which is a test of the PreferenceModule
. I have below 3 java files
UserPreference.java
package com.sigicn.preference;
import javax.inject.Inject;
import com.sigicn.commonmodels.Application;
public class UserPreference {
public String name, weiboAccount;
@Inject
public Application[] frequentlyUsedApps;
}
Then PreferenceModule.java
package com.sigicn.preference;
import javax.inject.Singleton;
import com.sigicn.commonmodels.Application;
import com.sigicn.utils.MiscUtils;
import dagger.Module;
import dagger.Provides;
@Module(library = true, complete = true)
public class PreferenceModule {
@Provides @Singleton UserPreference provideUserPreference() {
UserPreference userPreference = new UserPreference();
userPreference.frequentlyUsedApps = provideApplications();
return userPreference;
}
@Provides @Singleton Application[] provideApplications() {
return new Application[]{
new Application(
MiscUtils.generateUUID(), "Youtube"),
new Application(
MiscUtils.generateUUID(), "Pixi")
};
}
}
Then UserPreferenceTest.java
package com.sigicn.test.preference;
import javax.inject.Inject;
import com.sigicn.preference.PreferenceModule;
import com.sigicn.preference.UserPreference;
import dagger.Module;
import dagger.ObjectGraph;
import android.test.AndroidTestCase;
public class UserPreferenceTest extends AndroidTestCase {
@Module(injects = {UserPreference.class, UserPreferenceTest.class},
includes = PreferenceModule.class)
static class TestModule {
}
ObjectGraph objectGraph;
@Inject
UserPreference userPreference;
@Override
protected void setUp() throws Exception {
if (objectGraph == null) {
objectGraph = ObjectGraph.create(new TestModule());
}
super.setUp();
}
public void testFrequentlyUsedApps()
{
UserPreference localUserPreference = objectGraph.get(UserPreference.class);
assertNotNull(localUserPreference);
assertEquals(localUserPreference.frequentlyUsedApps.length, 2);
objectGraph.inject(this);
assertNotNull(userPreference);
assertEquals(userPreference.frequentlyUsedApps.length, 2);
assertSame(localUserPreference, userPreference);
assertSame(localUserPreference.frequentlyUsedApps, userPreference.frequentlyUsedApps);
}
}
But don't know why, that the frequentlyUsedApps
of UserPreference
is not injected as expected. Any idea why?
Update:
I think I have figured out the reason. It's because that I manually create UserPreference
and use it in the provider. If I remove the Provider for UserPreference
, and let Dagger to wire it automatically, then the field frequentlyUsedApps
does get injected. So it is my fault of not understanding Dagger well.
To inject an object in the activity, you'd use the appComponent defined in your Application class and call the inject() method, passing in an instance of the activity that requests injection. When using activities, inject Dagger in the activity's onCreate() method before calling super.
With the @Inject annotation on the constructor, we instruct Dagger that an object of this class can be injected into other objects. Dagger automatically calls this constructor, if an instance of this class is requested.
Dagger 2 is a compile-time android dependency injection framework that uses Java Specification Request 330 and Annotations. Some of the basic annotations that are used in dagger 2 are: @Module This annotation is used over the class which is used to construct objects and provide the dependencies.
I think you need to add some ObjectGraph#inject calls.
In each class where you have an @Inject annotation, you will also need a call to the inject method of the ObjectGraph you created.
I have had been struggling with this for a while also. I think the basic pattern is:
I started using a singleton rather than the Application class, because at least for now I have some places were I want to inject the app itself.
So here is what I am currently doing, which seems to work pretty weill
public class Injector {
private static Injector mInjector;
private ObjectGraph mObjectGraph;
private MyApp mApp;
private Injector() {
}
public static Injector getInstance() {
if (mInjector == null) {
mInjector = new Injector();
}
return mInjector;
}
protected List<Object> getModules() {
return Arrays.asList(
new ApplicationModule(mApp),
new AndroidModule(mApp)
);
}
public void inject(Object object) {
getObjectGraph().inject(object);
}
public ObjectGraph getObjectGraph() {
return mObjectGraph;
}
public void initialize(MyApp app) {
mApp = app;
mObjectGraph = ObjectGraph.create(getModules().toArray());
System.out.println(String.format("init object graph = %s",mObjectGraph.toString()));
}
}
Then in my application class I have a constructor like this:
public MyApp() {
System.out.println("myapp construtor");
Injector.getInstance().initialize(this);
Injector.getInstance().inject(this);
}
Then when I want to inject something I do this
@Inject Bus mBus;
public GcmBroadcastReceiver() {
Injector.getInstance().inject(this);
}
I have two modules , one for production and one for test
The production one has this
@Provides @Singleton
public Bus provideBus () {
return BusProvider.getInstance();
}
and the test one has this
@Provides @Singleton
public Bus provideBus () {
return mock(Bus.class);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With