So, what I am trying to accomplish is to ensure that I have only one instance per scope in Dagger2.
Default Singleton scope already works that way. No matter on how many places you inject same object, let's call it GlobalInstance, method GlobalInstance provideGlobalInstance() that constructs it will be called once and only once.
On the other side, if I define custom scope, for example #SessionScope and inside some SessionModule I make method User provideUser(), that method (and, consequentially, new User() constructor) will be called as many times as I am injecting User. No matter if I use the same module instance every time, User provideUser() is being called for every #Inject User mUser I have in my code, resulting with multiple instances, instead of one scope-limited "singleton".
Is there some clear way to achieve it, using regular Dagger api. One way to do it is to have lazy getters inside the module class, but it is not very clean way to do it.
Please note that #Singleton scope is functionally equivalent to any other custom scope you define.
It means that you could have two flavors of #Provides methods in SessionModule:
#Provides #SessionsScope - provides "session singletons" (more on this later)
#Provides - provides new object on each injection
Please note that the term "singleton" have some ambiguity when we talk about Dagger, therefore I prefere to use term "scoped objects". When scoped object injected with Dagger for the first time, the component caches its instance and returns it on each subsequent injections PERFORMED BY THE SAME COMPONENT.
For more information you can read this post: Android Dagger 2 Scopes Demistified
Related
I'm practicing dagger 2 for a week now, I just want to know the difference of these injections(constructor, method, field), and where should I use them.
Constructor: whenever you've the possibility to do so (when you have access to the constructor, for example, with your presenters if you use MVP pattern).
Field: when you don't have access to the constructor, for exemple when injecting in your Activity or Fragment.
Method: an #Inject annotated method will be executed by Dagger as soon as the construction call has finished. We usually use it when we want to pass class instance itself (this reference) to injected dependencies.
Read this for more informations and examples of use cases.
I'm creating an Android app and want to comply to clean architecture.
For example, I have an activity which has a presenter which creates use cases. In that inner layer, I have a repository interface (which is known by the use cases) which is implemented by a concrete repository, lets call it repsoitoryImpl (which is not known by the uses cases). What I did in previous projects was to create the presenter and the repositoryImpl in the activity, and pass the repositoryImpl as a repository to the presenter. The presenter can then, whenever there is an action coming from the activity (e.g. a button press) create a new use case and pass the repository to it.
This works, but a) the constructors of the use cases can become very long and b) the UI has knowledge of all other "outer" things, e.g. the repositoryImpl. So I thought DI to the rescue! And started to try out Dagger 2. However, my current solution does not seem to be "correct". What I would have liked is that I can just have an #inject annotated repository in a usecase and a repositoryImpl gets injected. However I found that, at the beginning of the "injection chain" I have to call inject() on the dagger component. In most of the examples, this is done in the activity. But then I would have to inject the presenter in the activity and the usecase into the presenter to be able to inject things into the use case. Is this correct? The problem is that I want to create the use cases dynamically with different parameters and not inject them.
So my current solution is to have the dagger "AppComponent" as a static field in the Android Application class and then in my use cases I call
Application.component.inject(this)
which allows me to inject things in the use case. But then the use cases have a dependency to dagger which doesn't comply to clean architecture. Because framework dependencies should only appear in the outer layer.
Is there a common solution to this problem? Am I understanding something wrong?
As u already pointed out in clean architecture use cases must not know about DI frameworks - even decorating use cases with framework specific attributes would be a smell.
As discussed here: How to handle UseCase Interactor constructors that have too many dependency parameters in DDD w/ Clean Architecture? having too many constructor parameters is usually an indicator that the use case is "doing too much". U should consider splitting them.
Furthermore the interfaces used by a use case to access "the details" (repository, external services and systems) should be designed in a way that they are most convenient for the use case. That means instead of having multiple repository interfaces and multiple service interfaces passed to a use case u could consider using façade pattern and design one or two interfaces which are more convenient for the use cases which then "aggregate" the work with the different repositories/services. This will also reduce the number of parameters passed to the constructor.
According to clean architecture the "composition" of ur application happens in the "main component" - a class living in the frameworks circle. There are objects are created and injected. If u want to create use cases dynamically u could have a factory pattern.
My Goal :
To understand how scope works and how to Implement a UserScope that I can use over multiple Activities and reset/create a new one as required.
Methods I am using :
This Blog: http://frogermcs.github.io/building-userscope-with-dagger2/
It apparently explains the same thing that i am trying to achieve here.
Official Docs
http://frogermcs.github.io/building-userscope-with-dagger2/
Quick brief on Blog
Obviously, There is UserModule and UserComponent. Author has wrapped the creation of UserComponent under UserManager which has ApplicationScope. So UserManager is available at time of log in. when login is successful UserComponent is initialized via UserManager. Simple logic.
Now this already initialized #UserScope is used in couple of Activities, as you can see in the picture.
What I am struggling to understand
Take a look at UserComponent.
public interface UserComponent {
#Subcomponent.Builder
interface Builder {
Builder sessionModule(UserModule userModule);
UserComponent build();
}
UserDetailsActivityComponent plus(UserDetailsActivityComponent.UserDetailsActivityModule module);
RepositoriesListActivityComponent plus(RepositoriesListActivityComponent.RepositoriesListActivityModule module);
LogoutManager logoutManager();
}
Specifically UserDetailsActivityComponent and RepositoriesListActivityComponent are created through UserComponent. Like this,
#Override
protected void onUserComponentSetup(UserComponent userComponent) {
userComponent.plus(new UserDetailsActivityComponent.UserDetailsActivityModule(this)).inject(this);
}
So they first get pre-created in UserComponent through UserManager and then it calls onUserComponentSetup which then creates the appropriate Component and injects the current Activity.
I fail to comprehend with this pattern mentioned above, as I have read in the docs that we use plus(InjectionToBeDoneOn i) when we need the injection on a particular instance of InjectionToBeDoneOn. But why inject this Activity via this Component? What does this accomplish? Wouldn't it make sense to do this the conventional way in onCreate() of the activity with DaggerXYZComponent().Builder().Build().inject(activity)?
Also, I am missing decent material of how UserScope is implemented in Android which has life span from log-in to log-out but not bigger than the #Singleton scope.
we use plus(InjectionToBeDoneOn i) when we need the injection on particular instance of InjectionToBeDoneOn
Not quite. A component has basically 3 kinds of methods
SomeDependency provideDependency() which just creates / provides some dependency to subcomponents, or for manual retrieval (basically a getter)
void inject(MyAndroidFrameworkClass object) that injects an object with its dependencies
SomeSubComponent plus(SubComponentModule module) that creates a subcomponent, adding additional modules
You're mixing up 2. and 3. here.
// user scoped component
userComponent
// create a subcomponent (UserDetailsActivityComponent)
.plus(new UserDetailsActivityComponent.UserDetailsActivityModule(this))
// use the UserDetailsActivityComponent that was just created and inject with it
.inject(this);
UserDetailsActivityComponent is a subcomponent of UserComponent, which is why the userComponent gets extended .plus(somemodule) to create a subcomponent. If your submcomponent does not need additional modules you can also just use .plus() because to Dagger the important thing is the return type or signature in general.
If it returns another component, then it creates a SubComponent.
If it hast one parameter and returns void or the parameters type, then it is an inject method
If it has no parameters and returns some type is is a provides method (1.) to expose some dependency
but why inject this Activity via this Component? What does this accomplish?
If you were to create UserDetailsActivityComponent from scratch, it would only see and know about what it can provide itself. If you have some #Singleton somewhere it could not access any of it, because it is not part of the object graph.
A subcomponent extends another component, adding to the object graph. If you have a #Singleton A and your UserComponentn needs A to provide B, with a subcomponent this will work, without it you will get a cannot be provided error.
Dagger is no magic. It really just builds up a directed graph and checks whether everything is fine. It will complain if some dependencies have cyclic dependencies on one another or if some part of the graph doesn't have access to dependencies it need.
Your UserComponent holds your userdata. For simplicity lets say it holds the UserName. Now UserDetailsActivity might want to display UserName, but it needs some way to get it.
By using the #Singleton AppComponent as a parent you'd have access to some Apis, but not the user scoped ones. You could move the user scoped objects into the #Singleton AppComponent, but then you'd either have to recreate the AppComponent every time the user changes (which kind of defeats the purpose of declaring it #Singleton, or you'd have to find some other means to update / change the user.
If you want to do it the Dagger way, you create a UserComponent that adds the User to the graph. That way subcomponents can access it and do their user things.
When the user changes you have to make sure to destroy any activities / fragments that used the UserComponent, and you just recreate everything—with a new user.
wont it make sense to do in conventional way in OnCreate() of the activity with DaggerXYZComponent().Builder().Build().inject(activity)
You can do that of course. The author just put the calls to app.getAppcomponent().getUserManager().getUserComponent() or something like this into their BaseActivity and BaseUserActivity so that you wouldn't have to repeat the same lines of code every time. This method will basically still be called in onCreate, it just enables you to use the components directly, without fetching them every single time.
You can obviously remove those template methods and inline everything in onCreate, leading to duplicated code, making maintenance harder in the long run.
i am missing decent material of how UserScope is implemented in android which has life span from log-in to log-out but not bigger than #SingleTon scope.
Android doesn't help and it's your job to clean up after yourself. If the user changes you purge everything the UserComponent and its SubComponents touched, and recreate it with the new user.
You will have to store the UserComponent with the current user either in the Application class, some "real" singleton, or some "Manager" in the application component with a #Singleton scope. Every approach has their own benefits I guess.
Scopes just point out to Dagger that one object should exist within a Scope only once. It doesn't matter what you name it, or how many objects are in the Scope. Dagger only needs them to ensure that there are no dependency cycles.
I'm currently trying to figure out Dagger 2. I am trying to set up 4 scopes: App, User, Activity, Fragment. User and Activity components are Subcomponents of App. Fragment is a Component with Activity as its dependency.
Say my UserSettingsActivity needs a Toolbar (provided by ActivityModule), and a UserProfile (provided by UserModule). I won't get a UserProfile until I ask for it from the database, whereas the Toolbar can be provided right away. So the order of injection that takes place is into ActivityComponent first, then into UserComponent. I have 2 #Inject fields, one for Toolbar and one for UserProfile in the activity. I was hoping that dagger will know that the dependencies are coming from different modules, but it seems to complain that UserProfile can't be provided when injected into ActivityComponent. Obviously it can't be provided by ActivityModule, but why is it not making a connection that UserProfile is provided by UserModule?
To my best knowledge, Dagger-2 doesn't support "partial injections".
Therefore, when you call myComponent.inject(this), Dagger-2 throws an error if myComponent can't provide all #Inject annotated members of this.
I see two ways to work around this limitation:
Remove #Inject annotation from UserProfile, expose UserProfile via public method in UserComponent and inject it manually when UserComponent is ready to be used. Something analogous to this: userProfile = userComponent.getUserProfile()
Don't make UserComponent dependent on data fetching. UserComponent could be used to inject Toolbar and some UserProfileProvider at the same time, and you will fetch UserProfile from UserProfileProvider when it is available.
I personally think that second approach is the better choice. DI libraries should be used in order to satisfy objects' dependencies at construction time. In Android we can't construct Activity or Fragment ourselves, therefore we perform DI in onCreate(), onAttach(), onCreateView(), etc., but it does not mean that we should be using DI libraries in order to assist in controlling the flow of applications.
Subcomponents work's similar to inheritance(extends), in your case User component and Activity component extending App component but there is no relation between User component and Activity component so when you request User dependency in Activity it will fail.
Subcomponent can't provide any dependency to other Subcomponent.
Instead, you can make Activity component as a subcomponent of User component. This will also give you the flexibility to switch user.
I have recently been integrating Dagger into a project that uses ContentProviders. I create a single ObjectGraph instance in my custom Application object, and basically in each managed component:
Activity,
Fragment,
Service
... Then, I call getApplication(), downcast to my custom Application object, and force the injection through some custom implementation in my Application class. This seems to be the prescribed method of performing injection based on the samples I've seen posted by the guys at Square.
This pattern doesn't hold for ContentProvider instances though as their lifecycle isn't as predictably tied to the lifecycle of the Application object, ie ContentProviders can be, and as I'm observing frequently are, created before the Application object is created (for reasons I have yet to comprehend).
so... does anyone have a nice way of injecting ContentProviders using Dagger? I've so far made it by having an isInjected() call at the beginning of each of my ContentProvider's interface methods (insert, query, update, delete)... basically a hacky form of lazy initialization. But this seems far from ideal. Is there a more prescribed approach to injecting ContentProviders?
The Application subclass is just a convention since it's usually the first object created. Our apps do not have content providers which is why we use them. There's nothing that says you can't put it somewhere else.
You can just use the traditional singleton pattern for instantiating and holding a reference to the ObjectGraph.
public final class Dagger {
static ObjectGraph og;
static ObjectGraph og() {
if (og == null) {
og = ObjectGraph.create(..);
}
return og;
}
}
The first person to access will initialize the instance which will be used for the lifetime of the process.
If your content provider is in a different process than your main application this solution will still work. Or you could simply create the graph when your content provider is created since it will be the only consumer. Normal multi-process rules still apply, of course, so no instances will be shared with the other processes.