Avoiding class scoped factories with RoboGuice - java

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);
}
}

Related

Android MVP - Share Preference

I started to learn MVP but I have a few questions related the SharedPreferences, as far as I know if I want to save a value in the sharedPreferences I need to pass this value to the presenter and the presenter calls the model to save the value, the same logic I would apply if I want to get or remove a value from the sharedPreference, but how is the best way to do that if I shouldn't pass the Context?
I sae a few code and the people used to pass the Context in the constructor method direct to the Model, but I still don't think that's a good idea.
Do you guys have any ideas?
Thanks,
Thales
Android specific imports should never exist in the Presenter if you want to keep it unit testable.
What you can do is, make an abstraction layer above SharedPreferences let's call it Cache, it would be an interface with all the needed caching methods, you would then provide a concrete implementation of it using SharedPreferences.
Here is a quick illustration of the idea:
interface Cache {
// Your caching methods
}
class CacheImpl implements Cache {
private SharedPreferences sharedPrefs;
public CacheImpl(Context context) {
// Takes a context to init sharedPrefs.
}
// implements all of Cache's methods
}
Then you would pass a reference for that implementation to the Presenter's constructor (better yet using DI to inject it to your presenters constructor):
Cache cache = new CacheImpl(myContext); // Naturally that would be an activity context
MyPresenter presenter = new MyPresenter(cache);
Then in your presenter you would receive that instance in the constructor:
private Cache cache;
public MyPresenter(Cache cache) {
this.cache = cache;
}
You can then use the cache variable without knowing about it's concrete implementation nor should you provide it a context.
Create a Storage class Object inside View and pass the context inside Storage Class constructor.
Then pass this storage class object in presenter (constructor) from View class.
Then whenever you need to save or get some data from your presenter - Then simply call the method of storage class from the object you have passed.
This way you will not need to send the context to your presenter.
View class
public class ViewClass extends ActionBarActivity {
private MyPresenter presenter;
private MyStorage storage;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
storage = new MyStorage(this);
presenter = new MyPresenter(this,storage);
}
}
MyStorage Class
public class MyStorage {
private Context mContext;
public MyStorage(Context context) {
this.mContext = context;
}
public void saveData(String data){
}
public String getData(){
return "";
}
}
MyPresenter class
public class MyPresenter {
private final ViewClass mView;
private final MyStorage mStorage;
public MyPresenter(ViewClass viewClass, MyStorage storage) {
this.mView = viewClass;
this.mStorage = storage;
}
}

How to use #Scope in Dagger 2

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.

Guice: instantiating a singleton before creating the module

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.

Dagger 2 activity injection not working

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.

Guice: Inject a class bound by another module?

I have the following classes:
public class CacheModule extends AbstractModule {
#Override
protected void configure() {
bindConstant().annotatedWith(Names.named(TIMEOUT")).to(60);
// ...etc.
}
}
public class DefaultCacheAdaptor implements CacheAdaptor {
private CacheModule bootstrapper = new CacheModule();
#Named("TIMEOUT") private int timeout;
// other fields omitted for brevity
public DefaultCacheAdaptor() {
super();
Injector injector = Guice.createInjector(bootstrapper);
#Named("TIMEOUT") int t = injector.getInstance(Integer.class);
setTimeout(t);
}
}
public class QueueModule extennds AbstractModule {
#Override
public void configure() {
bind(CacheAdaptor.class).to(DefaultCacheAdaptor.class);
}
}
public class DefaultQueueAdaptor implements QueueAdaptor {
private QueueModule bootstrapper = new QueueModule();
private CacheAdaptor cacheAdaptor;
public DefaultQueueAdaptor() {
super();
Injector injector = Guice.createInjector(bootstrapper);
setCacheAdaptor(injector.getInstance(CacheAdaptor.class));
}
}
The CacheModule/CacheAdaptor/DefaultCacheAdaptor is located in a different JAR than QueueModule/QueueAdaptor/DefaultQueueAdaptor, and so the latter JAR depends on the former JAR at runtime (obviously).
The purpose of coding things this way is to allow the CacheModule to boostrap/inject the entire object graph under DefaultCacheAdaptor when the user writes:
CacheAdaptor cacheAdaptor = new DefaultCacheAdaptor();
Ditto for the QueueAdaptor.
It just so happens to be that the QueueAdaptor gets injected with a CacheAdaptor.
However, DefaultCacheAdaptor is the "root" of its own object tree, and should always be injected by the CacheModule.
So I ask: how can I bind DefaultCacheAdaptor to CacheAdaptor from inside QueueModule, but ensure that the DefaultCacheAdaptor is itself initialized/bootstrapped by the CacheModule?
To be honest it sounds like this problem isn't actually one of Guice, but instead the standard problem across software engineering: ensuring your dependencies do what they claim to do. QueueModule shouldn't concern itself about whether DefaultCacheAdaptor holds up to its general contract. Instead, write a unit test for DefaultCacheAdaptor that guarantees that it bootstraps itself, then use it in QueueModule without a second thought.
This is especially true because DefaultCacheAdaptor has a completely unrelated injector tree. You should be able to use DefaultCacheAdaptor opaquely, and stop concerning QueueAdaptor with its implementation details. Its bootstrapping is part of its implementation, not its API.
Even if you were to merge the two Injector graphs into one (by injecting the Injector and calling createChildInjector, for instance), there's very little way to guarantee at compile time that bindings you need in other modules will exist, because Modules work at runtime. Your best bet is to write a unit test. You can fail a little faster by calling requireBinding, which will fail at Injector creation if that particular dependency doesn't end up satisfied externally.

Categories