Inject in Dagger an object with needs activity to be created - android-activity

Greeting all!
Please help me to figure out if the scenario, I need to cope with, which meets the Dagger concepts.
I have to inject a class into my Activity which needs this activity to be created. The only way comes to my mind is to add the activity to the Model and use it in the object Provides method. does it sound like a normal usage scenario.
#Module
public class SampleDiModule {
private Activity activity;
public SampleDiModule(Activity activity){
this.activity = activity;
}
#Provides
#ModuleScope
public InjectedObject provideInjectedObject(){
return new InjectedObject.createForAcivity(activity)
}
}
My intention to inject an activity presenter, the presenter depends on a object which could be created only by the object factory in the following way
public MyPresentor(InjectedObject object){
}
InjectedObject object = InjectedObjectFactory.forActivity(this)
Thanks

Ok, there are multiple ways to achieve this.
Two of them are on top of my mind.
First, using Dagger scopes. You can create #Activity scope which will manage objects that have life bound to life of particular activities. When creating dagger module that is scoped to Activity, you can pass an activity reference as constructor parameter, and then use it. Something like this (in pseudocode):
class ActivityScopedModule {
ActivityScopedModule(Activity: activity) {
this.activity = activity;
}
CustomObject provideCustomObject() {
return new CustomObject(this.activity);
}
}
Important thing is that modules that are scoped to activity must be instantiated from Activity.onCreate() Here you can find more about creating dagger scopes: http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/ Or in this three-part series: https://android.jlelse.eu/dagger-2-part-i-basic-principles-graph-dependencies-scopes-3dfd032ccd82
Another approach, the easier one, would be to, instead of using static InjectedObjectFactory.forActivity(this), to make it as non-static class InjectedObjectFactory, make it's instance in dagger module as new InjectedObjectFactory() and then from activity you call myInjectedObjectFactory.forActivity(this) and pass it to presenter.

Related

Issue while implementing a interface which extends to MongoRepository interface in Kotlin

I am trying to use the in built methods of MongoRepository<T,ID> interface to interact with mongo.
interface MovieRepository : MongoRepository<Movie, String> {
}
But when I try to implement the "MovieRepository" using class. Its asking me to implement all the member functions defined in "MongoRepository" as well
class ControllerClass(private val MovieRepository: MovieRepository): MovieRepository {}
This is what i get when i initialize my controller class:
Class 'ControllerClass' is not abstract and does not implement abstract member public abstract fun <S : Movie!> save(entity: S): S
Is there any way so that i do not need to defined all those MongoRepository's functions again in my ControllerClass?
You don't usually implement a repository interface yourself: you let Spring do it for you!
First, you define your interface, as you have done:
interface MovieRepository : MongoRepository<Movie, String> {
// Add any abstract methods you'll need here…
}
Then, you autowire a property of that type. In Kotlin, you can either do it in the primary constructor, e.g.:
#Controller
class ControllerClass #Autowired constructor(
private val movieRepository: MovieRepository
) {
// …code…
}
Or as a plain property. (In this case, because you can't specify an initial value, you have to make the property a var; it must either be nullable — requiring !! everywhere you use it — or, better, make it lateinit.)
#Controller
class ControllerClass {
#Autowired private lateinit var movieRepository: MovieRepository
// …code…
}
Spring will then create some synthetic class implementing that interface, and set your property to it. (You don't need to worry about how it does that — just as you don't need to worry about all the other magic it does, much of which involves creating synthetic subclasses. That's why Spring objects generally need to be made open — and why there's a Spring plugin which takes care of doing that.)
It's more usual to use the repository in a service class, and then call that from your controller class — at least, that pattern tends to scale better, and be easier to follow and to test. But doing so directly should work too. Either way, you can call whichever repository method you need, e.g. movieRepository.findAll().
See the Spring docs; they use Java, but it's mostly trivial to convert to Kotlin.

Dagger 2, scopes + annotation

I never worked with such a confusing DI-framework like dagger! - However, I try to wrap my head around it.
I have two scopes: ActivityScope and FragmentScope
On some of the samples provided StatisticsFragment.java you see e.g. the fragment annotated with the scope
#ActivityScoped
public class StatisticsFragment extends DaggerFragment implements
StatisticsContract.View {
...
}
Question 1:
Is this just documentation or not? In my app it makes no difference if I annotate the concrete fragment or not.
Question 2: Where in the generated code can I see which scope is used? My fragment injects a Presenter and an AuthProvider. The AuthProvider is annotated with Singleton (in AppModule), the Presenter is defined in UIModule -> LoginModule
looks like this:
UIModule.java:
#Module(includes = AndroidSupportInjectionModule.class)
public abstract class UIModule {
#ActivityScope
#ContributesAndroidInjector(modules = LoginModule.class)
abstract LoginActivity loginActivity();
#ChildFragmentScope
#ContributesAndroidInjector(modules = LoginModule.class)
abstract LoginFragment loginFragment();
#Binds
//#ChildFragmentScope
public abstract LoginContract.View loginView(final LoginFragment fragment);
}
LoginModule.java
#Module
public abstract class LoginModule {
#Provides
//#ChildFragmentScope
static LoginContract.Presenter provideLoginPresenter(final LoginContract.View view, final BaseStore store) {
return new LoginPresenter(view,store);
}
}
LoginFragemt.java
public class LoginFragment extends DaggerFragment {
#Inject
LoginContract.Presenter presenter;
#Inject
Provider<MyAuthClass> myAuthClass;
...
}
presenter is created every time the Fragment gets created, myAuthClass gets created only once and is singleton.
Perfect - but I have no idea HOW this works!!!
DaggerFragment#onAttach must somehow know that Presenter is a "local" singleton and MyAuthClass is a global-singleton ...
Scope is one of two ways you can tell Dagger to always bind the same object, rather than returning a newly-created one on each injection request. (The other way is the manual way: Just return the same object in a #Provides method.)
First, a scope overview: Let's say you have a component, FooComponent, which has a #FooScope annotation. You define a subcomponent, BarComponent, which has a #BarScope annotation. That means that using a single FooComponent instance, you can create as many BarComponent instances as you want.
#FooScoped
#Component(modules = /*...*/)
public interface FooComponent {
BarComponent createBarComponent(/* ... */); // Subcomponent factory method
YourObject1 getYourObject1(); // no scope
YourObject2 getYourObject2(); // FooScoped
}
#BarScoped
#Subcomponent(modules = /*...*/)
public interface BarComponent {
YourObject3 getYourObject3(); // no scope
YourObject4 getYourObject4(); // BarScoped
YourObject5 getYourObject5(); // FooScoped
}
When you call fooComponent.getYourObject1(), YourObject1 is unscoped, so Dagger does its default: create a brand new one. When you call fooComponent.getYourObject2(), though, if you've configured that YourObject2 to be #FooScoped, Dagger will return exactly one instance for the entire lifetime of that FooComponent. Of course, you could create two FooComponent instances, but you'll never see multiple instances of a #FooScoped object from the same #FooScoped component (FooComponent).
Now onto BarComponent: getYourObject3() is unscoped, so it returns a new instance every time; getYourObject4() is #BarScoped, so it returns a new instance for each instance of BarComponent; and getYourObject5() is #FooScoped, so you'll get the same instance along the instance of FooComponent from which the BarComponent was created.
Now to your questions:
Question 1: Is this just documentation or not? In my app it makes no difference if I annotate the concrete fragment or not.
In classes that have an #Inject-annotated constructor like StatisticsFragment does, adding a scope annotation is not simply documentation: Without the scope annotation, any requests to inject a StatisticsFragment will generate a brand new one. If you only expect there to be a single instance of StatisticsFragment per Activity, this may be surprising behavior, but it might be hard to notice the difference.
However, adding an #Inject annotation to a Fragment may be something of a controversial move, because the Android infrastructure is able to create and destroy Fragment instances itself. The object that Android recreates will not the scoped one, and it will have its members reinjected onAttach due to DaggerFragment's superclass behavior. I think a better practice is to drop the #Inject annotation from the constructor and stick with field injection for your Fragment. At that point you can drop the scope, because Dagger will never create your Fragment, so it'll never decide whether to create a new one or return an existing one.
Question 2: Where in the generated code can I see which scope is used? My fragment injects a Presenter and an AuthProvider. The AuthProvider is annotated with Singleton (in AppModule), the Presenter is defined in UIModule -> LoginModule
The generated code and scoping is always generated in the Component; subcomponents will have their implementations generated as an inner class of the Component. For each scoped binding, there will be a place in the initialize method where the Provider (e.g. AuthProvider) is wrapped in an instance of DoubleCheck that manages the double-checked locking for singleton components. If nobody asks Dagger to create an object (like StatisticsFragment), Dagger can determine the lack of component factory methods or injections in the graph, and can avoid adding any code generation for it at all—which might be why you're not seeing any.

Dagger and Object Graph Scoping with Flow/Mortar

So I've been spending a lot of time with Mortar and Flow this weekend, and I think I've finally worked most of it out. I've found that it's a little bit more complex than I originally thought, mostly because I haven't quite gotten my mind around Dagger's ObjectGraph Scoping, which Mortar relies on heavily. I've read as much as I could find on this on Dagger's site, but I find information on this subject lacking when it relates specifically to Dagger.
So I have a few questions:
1. I see examples of them scoping #Singleton's:
#Layout(R.layout.screen_friend)
public class FriendScreen implements Blueprint {
#Override public String getMortarScopeName() {
return getClass().getName();
}
#Override public Object getDaggerModule() {
return new Module();
}
#dagger.Module(
injects = FriendView.class
)
static class Module {
}
#Singleton
public static class Presenter extends ViewPresenter<TestView> {
#Inject
public Presenter() {
Log.d("FriendScreen", "Friend Presenter Created");
}
#Override protected void onLoad(Bundle savedInstanceState) {
super.onLoad(savedInstanceState);
}
}
Is Presenter in this case scoped to this Module specifically because it's an inner class?
2. How can I make sure that an instance of it is only created in this Object Graph but not the global application object graph?
2. What if the Presenter was too big, and I wanted to move it to it's own separate class? How would I scope it just to this module?
3. I noticed that some of the Module classes in their examples are static, and others aren't. Does this have any effect on scoping?
4. Where can I read more to better understand Dagger's Object Graph. I need to get a better understanding of includes, injects, addsTo and how those are used in ObjectGraph creation
etc:
#dagger.Module( //
includes = ActionBarModule.class,
injects = MainView.class,
addsTo = ApplicationModule.class, //
library = true //
)
I don't believe presenters are scoped to a module since on a rotation they are preserved. the #Singleton annotation also leads me to believe that a presenter is on a global graph and just binds to a view when an activity recreates itself.
Here's a good scoping source.
Effective Java has a fantastic explanation about static inner vs non static inner vs anonymous classes if you want to learn more about those.

Customise the creation of a gin managed object or creating two different instances of the same class

I want to be able to create two instances of the same class and have them be injected with different properties and then have those two objects injected into two specific locations in my application.
Currently I have a method in my ClientModule...
#Provides
#Named("bean1")
public MainBean getMainBean() {
MainBean mainBean = new MainBean(new SecondaryBean());
return mainBean;
}
And then in my presenters etc I do the following:
public MyPresenter(final EventBus eventBus, final MyView view,
#Named("bean1") MainBean bean, TitleSetupData data) {
super(eventBus, view);
this.bean1 = bean1;
}
And it works great. Based on the #Named annotation corresponding I get the correct bean.
However, this approach has a weakness in that I need to create and inject all the dependencies of MainBean in the #Provides method.
So any #Inject annotations of SecondaryBean are not honoured for example.
One thing I could do is pass into the getMainBean method any relevant dependencies but I'm wondering if there might be another more elegant or better solution.
Anyone got any ideas?
I came across the same problem.
What you are looking for is #Assisted Inject, where some of the constructor parameters are injected, and some are passed as arguments when you instantiate your object.
You can find a full example at this blog post which helped me getting started.

MVVM share object between the all the views

I have MVVM Project and I want to share one object( singleton ) from the model between several viewmodel what is the good practice to do that?
Thank you for the help
If the object is needed and does not provide value without it force the interface within the object via Constructor Injection; do not push a concrete type via injection always make use of an interface.
Since you are not making use of an IoC container such as Unity, you will need to create your singleton instance at the startup of your application and then make sure that the given instance is passed in via the given ViewModels constructor as needed.
A better approach would be pushing the singleton instance to a service which can provide the needed behavior and then disregard pushing the singleton into the Model. This would be a more MVVM purist approach and will separate concerns across your Models/ViewModels.
EDIT:
If you were making use of Unity you would define a Lifetime Manager at the time of registration.
// Register a type to have a singleton lifetime without mapping the type
// Uses the container only to implement singleton behavior
myContainer.RegisterType<MySingletonObject>(new ContainerControlledLifetimeManager());
// Following code will return a singleton instance of MySingletonObject
// Container will take over lifetime management of the object
myContainer.Resolve<MySingletonObject>();
Once you do this any attempt to resolve MySingletonObject via the IUnityContainer would resolve to the same instance providing the singleton behavior you so desire across the application. ViewModels themselves should not need to have the same instance returned. The data it needs should be abstracted away via a service as referenced earlier which could potentially behave like a singleton and provide a stateful implementation if needed but the ViewModel should not need to be a singleton. If you find yourself making either a Model or ViewModel a singleton; take a step back and analyze your design.
If you have control over all viewmodels then an easy approach (that I've used personally) is to just put a static variable on the base class of all viewmodels and make that accessible to all inheritors (either protected or even public if its useful outside of the viewmodels).
It's good practice anyway to have a common base class for your viewmodels since it allows you to implement property notification in one place (and other common functionality, like messaging etc.) instead of replicating it in all viewmodels.
Something like this is what I've used in my projects:
public class MyViewModelBase : INotifyPropertyChanged
{
private static MySharedSingleton _sharedObj;
static MyViewModelBase()
{
_sharedObj = new MySharedSingleton(/* initialize it here if needed */);
}
// or public
protected MySharedSingleton SharedObject { get { return _sharedObj; } }
// INotifyPropertyChanged stuff
// ...
}
public class SomeViewModel : MyViewModelBase
{
void SomeMethod()
{
SharedObject.DoStuff();
}
}
If the construction of the shared singleton object is heavy, you can of course use any of the standard techniques for lazy instantiation of it.
I would suggest that you inject the dependency into each view model (either constructor or property injection for example), and always work against abstractions in your view models, so that your dependency can easily be mocked or replaced as required. You then just need to ensure that each view model uses the same instance of your type - if you are using an IoC container, you can register a shared instance of your type easily.
I use a separate class for my global singleton with a model. This relieves me of agonizing over how to inject this model into view models and other models. E.g.
The singleton:
public class ApplicationModel
{
public string LoggedOnUser { get; set; }
// Etc.
private ApplicationModel() {
// Set things up.
}
private static ApplicationModel _active;
public static ApplicationModel Current {
get {
if (_active == null) {
_active = new ApplicationModel();
}
return _active;
}
}
}
The view model that needs to hold no reference to the singleton:
public class SomeViewModel
{
private string _user;
public SomeViewModel() {
_user = ApplicationModel.Current.LoggedOnUser;
}
}