I'm trying the new dagger 2, it's my first time implementing it but I can't make it work. I think I got the concept and I understand the example here
I try to copy the same structure just a bit modified for my example.
Here is the AppComponent that extends the Graph where I defined the classes I want.
#ApplicationScope
#Component(modules = {AppModule.class, DataModule.class})
public interface EFAppComponent extends EFGraph {
/**
* An initializer that creates the graph from an application.
*/
public final static class Initializer {
private Initializer() {
} // No instances.
public static EFAppComponent init(EFApp app) {
return Dagger_EFAppComponent.builder()
.appModule(new AppModule(app))
.build();
}
}
}
public interface EFGraph {
public void inject(EFApp app);
public ImageLoader imageLoader();
public EventBus eventBus();
}
Then inside each module I'm providing the corresponding classes. From here everything works good and Dagger seams to build the Dagger_EFAppComponent correctly.
Then in the Application class I init using the constructor
component = EFAppComponent.Initializer.init(this);
component.inject(this);
Then my goal is to Inject ImageLoader and EventBus in my activity. To do that I create a ActivityComponent.
#ActivityScope
#Component(
dependencies = EFAppComponent.class,
modules = ActivityModule.class
)
public interface ActivityComponent {
public void inject(BaseActivity activity);
}
Then from my activity I call inject.
activityComponent = Dagger_ActivityComponent.builder()
.eFAppComponent(component)
.activityModule(new ActivityModule(this))
.build();
activityComponent.inject(this);
So because I declared #Inject EventBus eventBus in my activity after the inject method call should be injected. Well it's not.
So after debugging and tracking step by step my app and the example I realized that the Dagger_ActivityComponent is not build correctly.
private final ActivityModule activityModule;
private final EFAppComponent eFAppComponent;
private Dagger_ActivityComponent(Builder builder) {
assert builder != null;
this.activityModule = builder.activityModule;
this.eFAppComponent = builder.eFAppComponent;
initialize();
}
Were the initialize method is empty and no Provider are declared as variable.
Am I missing something? I've been the full day trying to make it work but I'm not success.
Appreciate the help.
Well... After the full day spend on this I decide to post it and after 5 minutes I found the solution.
I'm using a BaseActivity for all my activity, and I thought I could use this to inject my components but seams this is not possible.
So I just change this line in my ActivityComponent
public void inject(BaseActivity activity)
to
public void inject(MainActivity activity)
So to the name of the activity where I'm injecting the dependencies...
What brings me to a new question. How can I implement a base component to handle all my activities? or I must create a Component for each view/activity/fragment I want to have DI?
#Marcel, I recently migrated a project from Dagger 1.2 over to 2.0. I had similar solution where abstract BaseActivity injected the dependencies by doing something along the lines of "application.inject(this);". With Dagger 2.0 this is not possible (as of now) as mentioned in the comment above.
One of the ways I got around this was by changing the "inject" method in the Application class itself to strong type the object. For Example..
class MyApp extends Application {
...
public void inject(Object activity) {
if (activity instanceof MainActivity) {
mComponent.inject((MainActivity) activity);
} else if (activity instanceof SubActivity) {
mComponent.inject((SubActivity) activity);
}
}
}
With that I did not have to change anything in my existing classes.
FYI: There is a project called Bullet by #thomas-broyer that does this too.
Related
So I have some code that runs an algorithm, say with an AlgoRunner class. Now this AlgoRunner class can be implemented in multiple ways to run different algorithms using Algo classes. I want to use Dagger 2 to provide different implementations of the AlgoRunner class to a "Manager" class that passes input to AlgoRunner as well as other components that it manages.
Question
I have the following right now, but I'm not sure if this is the correct way, mainly because of that empty AlgoRunnerProvider module. Is that any other way to achieve what I'm trying to do? Or to simplify what I have?
Should I just create different components, OneAlgoRunnerComponent and TwoAlgoRunnerComponent and inject the Manager from each of those?
The class that constructs the Manager instance uses this component to inject the AlgoRunner into that instance so that the Manager can pass it the inputs.
#Component(
modules = {
AlgoRunnerProvider.class
}
)
public interface AlgoRunnerComponent {
void inject(Manager manager);
AlgoRunner getAlgoRunner();
}
AlgoRunnerProvider Module
#Module
public class AlgoRunnerProvider {
#Provides
public AlgoRunner getAlgoRunner() {
return null;
}
}
OneAlgoRunnerProvider, that overrides the provides method in AlgoRunnerProvider.
Could have a TwoAlgoRunnerProvider as well, that does the same thing and provides TwoAlgoRunner, as long as that extends AlgoRunner.
public class OneAlgoRunnerProvider extends AlgoRunnerProvider {
private final OneAlgo algo;
public OneAlgoRunnerProvider(OneAlgo algo) {
this.algo = algo;
}
#Override
public OneAlgoRunner getAlgoRunner() {
return new OneAlgoRunner(algo);
}
}
All this is used like this right now:
AlgoRunnerComponent build = DaggerAlgoRunnerComponent.builder()
.algoRunnerProvider(new OneAlgoRunnerProvider(new OneAlgo()))
// .algoRunnerProvider(new TwoAlgoRunnerProvider(new TwoAlgo()))
.build();
Manager manager = managerComponent.getManager();
build.inject(manager);
Truth.assertThat(manager.algoRunner).isInstanceOf(OneAlgoRunner.class);
// Truth.assertThat(manager.algoRunner).isInstanceOf(OneAlgoRunner.class);
Thanks a lot!
The dagger framework is used to handle object creation for you. If you start doing some sort of initialization in one of your classes you wish to provide, there is probably something not as it is supposed to be (see getAlgoRunner()).
If you have different types that you want to provide at runtime, you want a factory of some sorts to create the correct object. Enter dagger.
You have multiple ways of achieving what you want. Basically, the module should handle the object creation:
#Module
public class AlgoRunnerProvider {
#Provides
public AlgoRunner getAlgoRunner() {
// todo create the correct type
return null;
}
}
1. #Named annotation (or some other Qualifier)
If you know at compile time which class is going to need which type, you should use qualifiers.
#Named("Version1")
#Inject
AlgoRunner mRunner;
You then just can provide different implementations from your module:
#Provides
#Named("Version1")
public AlgoRunner getAlgoRunner() {
return new Version1AlgoRunner();
}
#Provides
#Named("OtherVersion")
public AlgoRunner getAlgoRunner(Depends someOtherDependency) {
return new OtherVersionAlgoRunner(someOtherDependency);
}
2. Switching at runtime
While you could always use the first option by creating multiple classes with different dependencies, you might want to be able to chose at runtime. For this, you need to pass in some argument to your module:
#Module
public class AlgoRunnerProvider {
private final int mType;
public AlgoRunnerProvider(int type) {
mType = type;
}
#Provides
public AlgoRunner getAlgoRunner() {
if(mType == TYPE_A) {
return new Version1AlgoRunner();
} else {
return new OtherVersionAlgoRunner();
}
}
}
With this variant you still have your creation logic inside your module, where your dependencies come from.
3. Use different modules
Another approach would be to use different modules. This will only be a clean solution if determined at compile time (different classes using different modules) and not some choosing logic at runtime in the same class.
If you start writing code like if typeA then moduleA else moduleB you should probably stop and do something else.
You can use the same component but create it using different modules for different classes by using good old inheritance. Every module just provides its implementation of AlgoRunner.
// one class using one module to get a specific behavior
public class MyClassVersionA {
public void onCreate(Bundle saved) {
component.myModule(new MyModuleVersionA()).build();
}
}
// another class using a different module to get a different behavior
public class MyClassSomethingElse {
public void onCreate(Bundle saved) {
component.myModule(new MyModuleSomethingElse()).build();
}
}
You would then just subclass your module accordingly like so
// did not test the following, something like this...
public abstract class MyModule {
#Provides
public AlgoRunner getAlgoRunner();
}
public class MyModuleVersionA extends MyModule {
#Provides
#Override
public AlgoRunner getAlgoRunner() {
return new Version1AlgoRunner();
}
}
public class MyModuleSomethingElse extends MyModule {
#Provides
#Override
public AlgoRunner getAlgoRunner() {
return new SomeOtherAlgoRunner();
}
}
There are probably even more possibilities, especially if starting to mix those approaches, but I think those 3 to be the basic tools that you can use.
I read a lot of material on the #Scope annotation but still not fully understanding if what I know is correct.
Can someone explain what exactly is #Scope for? Where is it used? How is it used?
Is it only used when defining the component?
Also is a scope defined like this?:
#Scope
public #interface SomeScope {
}
And used like this?:
#SomeScope
#Component(modules = {
HeaterModule.class,
PumpModule.class
})
public interface MainActivityComponent {
void inject(MainActivity mainActivity);
CoffeeMaker maker();
}
The definition of scopes for Java EE applications states the following:
For a web application to use a bean that injects another bean class,
the bean needs to be able to hold state over the duration of the
user’s interaction with the application. The way to define this state
is to give the bean a scope.
Let's associate it with Android. Scopes impose certain limitations in terms of dependencies lifecycle provided by a scoped provider.
For example, let's say we want to be provided with #Singleton dependency obtainable from #ActivityScoped component. The component lives as long as the Activity. Once activity is destroyed and created again, our component is instantiated accordingly and our '#Singleton' dependency is also created once again.
Summing up, our #Singleton dependencies live as long as the #Components they are associated with - this is I think most practical explanation.
Internally, once Dagger notifies within the #Component the provision method with the specified scope, it creates a ScopedProvider for dependency provision. Otherwise, a Factory is created.
The ScopedProvider's get method is a double-check singleton method:
public T get() {
// double-check idiom from EJ2: Item 71
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
instance = result = factory.get();
}
}
}
return (T) result;
}
To see a practical #Scope usage you can take a look at one of the examples of mine:
https://github.com/dawidgdanski/AccountAuthenticatorExample
Hope, that was helpful somehow.
EDIT 1:
The article provided by #Fshamri explains it even better.
EDIT 2:
Let's consider the following structure :
The Component:
#ActivityScope //Dagger ignores the annotation put atop the #Component. I put it there just for readability
#Component(dependencies = DependencyGraph.class,
modules = {ActivityModule.class})
public interface ActivityComponent {
void inject(MainActivity mainActivity);
void inject(SignUpActivity signUpActivity);
void inject(SignInActivity signInActivity);
And the module supplying the dependencies:
#Module
public class ActivityModule {
private final Activity activity;
public ActivityModule(Activity activity) {
this.activity = activity;
}
#Provides
#ActivityScope
MainView provideMainView() {
return (MainView) activity;
}
#Provides
SignInView provideSignInView() {
return (SignInView) activity;
}
}
The #ActivityScope extends the #Scope annotation - it is interpreted by Dagger the same way as the #Singleton is. The ActivityModule provides 2 views: the #ActivityScoped MainView and the SignInView without any scope. During the compilation time Dagger's annotation processor creates Providers for both views. The difference between the MainView's and the SignInView's generated Provider is that for the MainView Dagger generates the ScopedProvider (because we explicitly request this kind of provider with #ActivityScope) whereas for the SignInView Dagger generates regular Factory provider.
The contract of the ScopedProvider looks like the one above. The contract for the Factory provider, however, looks the following way:
#Generated("dagger.internal.codegen.ComponentProcessor")
public final class ActivityModule_ProvideSignInViewFactory implements Factory<SignInView> {
private final ActivityModule module;
public ActivityModule_ProvideSignInViewFactory(ActivityModule module) {
assert module != null;
this.module = module;
}
#Override
public SignInView get() {
SignInView provided = module.provideSignInView();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-#Nullable #Provides method");
}
return provided;
}
public static Factory<SignInView> create(ActivityModule module) {
return new ActivityModule_ProvideSignInViewFactory(module);
}
}
Conclusions:
1. The ScopedProvider is a classical double-check singleton pattern. It guarantees to create only one instance of the dependency.
2. The Factory's get() method just distributes the dependency from the module which means it can distribute new instance of the dependency each time it is requested (in fact, in the example the Activity is only cast to the SignInView which still gives us a single instance but this is copy-pasted logic from my example).
3. Dagger cares about #Scopes provided along with provision methods in the #Modules, not the #Components.
I encourage you to download the sample and build the project, then to see the contract of the generated Dagger components and modules.
Hope this is more understandable now.
have you looked at this article?
In Dagger 2 scopes mechanism cares about keeping single instance of
class as long as its scope exists. In practice it means that instances
scoped in #ApplicationScope lives as long as Application object.
#ActivityScope keeps references as long as Activity exists (for
example we can share single instance of any class between all
fragments hosted in this Activity). In short - scopes give us “local
singletons” which live as long as scope itself.
How can you override dependencies within different scopes of Dagger 2? Example:
I have two components in my app: ApplicationComponent and ActivityComponent. ApplicationComponent is the base component and ActivityComponent is a scoped component where I want to perform the override.
For this example I created those models:
public class Parrot {
private final HelloPrinter helloPrinter;
public Parrot(HelloPrinter helloPrinter) {
this.helloPrinter = helloPrinter;
}
public void sayHello(){
helloPrinter.print();
}
}
public interface HelloPrinter {
void print();
}
public class AppHelloPrinter implements HelloPrinter{
#Override
public void print() {
System.out.println("Hello Application");
}
}
public class ActivityHelloPrinter implements HelloPrinter {
#Override
public void print() {
System.out.println("Hello Activity");
}
}
And the code:
ApplicationComponent applicationComponent = DaggerApplicationComponent.builder().build();
applicationComponent.provideParrot().sayHello();
activityComponent = DaggerActivityComponent.builder()
.applicationComponent(applicationComponent).build();
activityComponent.provideParrot().sayHello();
My desired output is:
Hello Application
Hello Activity
So I made the modules:
ApplicationModule:
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
Parrot provideParrot();
}
#Module
public class ApplicationModule {
#Provides
#Singleton
HelloPrinter providePrinter(){
return new AppHelloPrinter();
}
#Provides
Parrot provideParrot(HelloPrinter helloPrinter) {
return new Parrot(helloPrinter);
}
}
ActivityModule: Attempting to override the HelloPrinter
#PerActivity
#Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
public interface ActivityComponent {
Parrot provideParrot();
}
#Module
#PerActivity
public class ActivityModule {
#Provides
#PerActivity
HelloPrinter provideHelloPrinter() {
return new ActivityHelloPrinter();
}
}
But with this config the output is:
Hello Application
Hello Application
What do I am doing wrong? Thanks
The short answer is...you can't do that.
With dagger everything is done at compile time.
You have an application component, that knows how to construct a HelloPrinter and a Parrot.
You then expose the Parrot for all Components to use.
You have your activity component, that also knows how to construct a HelloPrinter!
So what happens?
Keep in mind the object graph. Components know what they can build and depend on other components, exposing known objects themselves.
applicationComponent.provideParrot().sayHello();
This one is easy. You create the component, you want a parrot and it is constructed using the known Printer.
activityComponent.provideParrot().sayHello();
What happens here, is (basically) the same. You say you want a parrot. Your activity component does not know how to make one, it just knows how to make a printer!
But wait. It has a dependency on an application component, conveniently exposing a Parrot Factory.
The application components factory gets called and the parrot gets instantiated. Since the application module knows how to build a printer, it uses the one at hand.
...now what
So...you could provide Parrots in your activity component, they then would use a different printer!
Gradle: error: Parrot is bound multiple times
Here we would get 2 Parrots into our object graph, since there is no "overwriting" happening. This won't work, and shouldn't.
Conclusion
There is no way to override methods. As soon as you declare a second Parrot or HelloPrinter it will fail compilation.
The only possiblity to achieve a similar functionality would be to use #Named() annotations on which printer to use and / or pull the whole parrot creation down into the activity module.
And please correct me if I am missing something, but I don't even see a way to keep the signature the same with using named annotations.
Is it possible to instantiate and assign a singleton to a reference with Guice before creating the Module and pass that instance to the Module constructor be bound during configuration?
Here is an example of what I mean:
I have a method that allows me to create objects depending on a custom implementation of an interface which is being passed in constructor as an Optional (if the user won't provide a custom implementation, we will use the default one), which is being done by binding the interface to that particular implementation in the Module class. :
public static MyClass createMyClassObject(Optional<SpecialInterface> customSpecialInterfaceObject) {
SpecialInterface specialInterfacebject;
if(customSpecialInterfaceObject.isPresent() {
specialInterfaceObject = customSpecialInterfaceObject.get()
} else {
/* here I would like to bind it to an instance of the DefaultSpecialInterfaceObject but can't really do something like:
Injector injector = Guice.createInjector(myClassModule);
DefaultSpecialInterface instance = injector.getInstance(DefaultSpecialInterface.class);
as the module is yet to be created */
}
MyClassModule myClassModule = new MyClassModule(specialInterfaceObject);
Injector injector = Guice.createInjector(myClassModule);
return injector.getInstance(MyClass.class);
}
I'm currently using classes instead of instances to solve this problem, such as in the example below, but I don't quite like this solution. Would be happy to see a better way of doing it:
private static Class resolveSpecialInterfaceObject(Optional<SpecialInterface> customSpecialInterfaceObject) {
Class specialInterfaceObjectClass;
if (customSpecialInterfaceObject.isPresent()) {
specialInterfaceObjectClass= customSpecialInterfaceObject.get().getClass();
} else {
specialInterfaceObjectClass = DefaultSpecialInterface.class;
}
return specialInterfaceObjectClass;
}
public abstract class MyClassModule extends AbstractModule {
private final Class<SpecialInterface> specialInterfaceObjectClass;
public MyClassModule(Class<SpecialInterface> specialInterfaceObjectClass) {
this.specialInterfaceObjectClass= specialIntefaceObjectClass;
}
#Override
protected void configure() {
bind(SpecialInterface.class).to(specialInterfaceObjectClass);
}
}
Edit, from a comment below:
one more thing- didn't want to make the question too long; actually, I also want to perform another operation on the resulting instance of SpecialInterface, but only if it is the instance of DefaultSpecialInterface and I don't think it should be done in the Module. I was thinking if I could just have this bean up and running before, such as in Spring, so I could just pass it to the Module, but also use it in another method call before?
Can you take the whole Optional and use bind(...).toInstance(...)?
public static MyClass createMyClassObject(
Optional<SpecialInterface> customSpecialInterfaceObject) {
MyClassModule myClassModule = new MyClassModule(customSpecialInterfaceObject);
Injector injector = Guice.createInjector(myClassModule);
MyClassFactory instance = injector.getInstance(MyClassFactory.class);
return instance.createMyClassObject();
}
class MyClassModule extends AbstractModule {
private final Optional<SpecialInterface> customObject;
MyClassModule(Optional<SpecialInterface> customObject) {
this.customObject = customObject;
}
#Override public void configure() {
if (customObject.isPresent()) {
// Singleton by necessity: Guice doesn't know how to create another one.
bind(SpecialInterface.class).toInstance(customObject.get());
} else {
// Default scoped. Add ".in(Singleton.class)" if necessary.
bind(SpecialInterface.class).toInstance(DefaultSpecialInterfaceClass.class);
}
}
}
If you want to perform additional initialization on DefaultSpecialInterface and nothing else, you have a number of options:
If some kind of initialization is important for all implementations and likely too heavy to put into a class constructor, add an initialize method on your SpecialInterface. Make the custom one a no-op, and implement it for DefaultSpecialInterface.
If the initialization is unique to DefaultSpecialInterface, I see no reason why it shouldn't be in the Module. Write a #Provides method or bind to a Provider<SpecialInterface> that creates and initializes DefaultSpecialInterface correctly.
If your real goal is to keep the business logic out of a Module, you can do so by extracting it into a free-standing Provider or DefaultSpecialInterfaceFactory that is responsible for that.
Remember, Guice is responsible for feeding fully-constructed objects into your object graph, and that means that injecting a SpecialInterface should get a ready-to-use implementor of the SpecialInterface general contract. If Guice needs to perform some initialization to make that happen, it's not unreasonable to have it do so, and a Module isn't a bad place to do it.
I'm trying to use a Model-View-Presenter pattern in my Android project. I am using the excellent RoboGuice project with AssistedInject to manage my dependencies. I am struggling with the style of creating instances of my presenters.
AssistedInject appears to require me to first inject a factory to create a presenter and then use that factory to create an instance of a presenter. Injection (appears) to only work at the class scope level; I cannot inject local variables. My methods do not need both a factory and a presenter; I only care about the factory long enough to generate a single presenter. I'd like to avoid keeping the mostly useless factory around.
More Detail
In my implementation of the pattern, I choose for each presenter and view to hold a reference to the other. A presenter must usually be passed one or more "Service" objects that are used to interact with the model. An Android Activity is an implementation of a (MVP) View. An Activity must be the composition root of any Android application. Therefore, each activity must instantiate a presenter, and that presenter needs a service as well as a reference to the view.
In general, presenters look like
public class GreatStuffPresenter {
private final SomeService service;
private final GreatStuffView view;
#Inject
public GreatStuffPresenter(SomeService service, #Assisted GreatStuffView view) {
this.service = service;
this.view = view;
bind();
}
public void bind() {
Record r = service.getSomeRecord();
view.setField(r.field);
}
}
and Activites look like
public class GreatStuffActivity extends RoboActivity {
#Inject private final GreatStuffPresenterFactory presenterFactory;
private GreatStuffPresenter presenter;
#Override
public void onCreate(...) {
super.onCreate(savedInstanceState);
setContentView(R.layout.create_update_record);
presenter = presenterFactory.create(this);
}
}
Now What?
I am dissatisfied that I must scope the presenterFactory at the instance level; I only need it during onCreate(). Am I missing some additional magic that RoboGuice could perform for me? If not, is there a better practice or pattern I should be using to avoid this unnecessary scoping?
In the end, I decided to get the RoboGuice injector, ask it for an instance of my factory, and create the presenter I'm looking for. I am reasonably happy with this approach; I'm not polluting my class with variables I won't use, and the line seems reasonably simple.
public class GreatStuffActivity extends RoboActivity {
private GreatStuffPresenter presenter;
#Override
public void onCreate(...) {
super.onCreate(savedInstanceState);
setContentView(R.layout.create_update_record);
presenter = RoboGuice.getInjector(this).getInstance(GreatStuffPresenterFactory.class).create(this);
}
}