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.
Related
I have property data manager in Activity A and I am instantiating it's value instance in activity A onCreate() through dagger component.
override fun onCreate(savedInstanceState: Bundle?){
datatManager = coreComponent().provideDataManager()
}
My questions(probably a silly ones) are: 1] Does dagger generate the code and instantiate the object when I call it on onCreate()? or Dagger being compile time, it already have all the classes ready behind the scene on which Data Manager has dependency? and just pas me the reference when I need it? 2] Does this make creating/starting an activity any slower?
Dagger generates code during compilation time, so the code itself is "ready", but that doesn' mean class instances are. Dagger creates instances every time you access them by default, unless you use a scoping mechanism such as #Singleton.
If an injected instance is heavy (i.e. does a lot in its constructor) then yes, it can negatively affect your activity creation time.
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.
Is there a way in Dagger2 or in Dagger2 Android Injection support to inject the member instances without specifying the class names of the fragments.
I have a modular project where
The following line is asking to provide a binder Factory for the injectable class.
#Override
public void onAttach(Context context) {
AndroidSupportInjection.inject(this);
super.onAttach(context);
}
But my intention is to provide the injecting members through different modules in the project, where the I wouldn't need to specify the class name of the Fragment at all.
Is this possible in Dagger2 injection or not?
Is there a way in Dagger2 or in Dagger2 Android Injection support to inject the member instances without specifying the class names of the fragments.
tl;dr No. You always need a component that contains a .inject(FragmentInQuestion fragment) method for every Fragment you want to inject.
Dagger uses annotation processing at compile time to resolve all of your .inject(SomeFragment fragment) methods where it looks up fields annotated with #Inject and creates code to inject them.
It needs the actual class name, since it will only generate code for the class used with its fields.
class Fragment {
// no #Inject annotated fields, part of framework!
}
class SomeFragment extens Fragment {
#Inject SomeDependency dep;
}
class OtherFragment extens Fragment {
#Inject OtherDependency dep;
}
Declaring one generic component that injects all your fragments is impossible.
.inject(Fragment fragment) would not inject any properties, since Fragment does not contain any #Inject annotated fields. So neither of the dep fields in the above sample would be provided and they both would be null.
You could create a BaseFragment that contains common objects and write an injection for it, but again, any annotated fields of its children would not be supplied.
You could try some other workarounds, but in the end it would always mean that you'd be injecting or be working with a base type. While this might be feasible in some situations, I don't think it would work on more than some special edge cases.
The Android Injection part of Dagger 2 takes this approach and creates a generic interface that your components have to implement along with a Builder to bind the type in question.
interface AndroidInjector<T> {
inject(T instance)
}
By implementing this interface AndroidInjection can then look up (and create) the correct component and inject your Fragment. For the reasons mentioned above this will always be the actual class of your Fragment, and not some base type.
So by using the Android Injection part you won't be able to use some common base class, and even without it you'd have a hard time.
If you're looking for a way to move out the call of AndroidInjection.inject(this) to somewhere else you should look at the Google Android Architecture Components sample project where they use FragmentLifecycleCallbacks to inject the fragments globally at the right time.
One of the most up to date samples covering Android Architecture Components is GithubBrowserSample provided by Google. I reviewed the code and a few questions arose:
I have noticed that ViewModelModule is included in AppModule. It means that all the viewmodels are added to the DI graph. Why that is done in that way instead of having separate Module for each Activity/Fragment that would provide only needed ViewModel for specific Activity/Fragment?
In this specific example, where viewmodels are instantiated using GithubViewModelFactory is there any way to pass a parameter to the specific ViewModel? Or the better solution would be to create a setter in ViewModel and set needed param via setter?
[...] It means that all the viewmodels are added to the DI graph. Why that is done in that way instead of having separate Module for each Activity/Fragment [...]?
They are added to the DI graph, but they are not yet created. Instead they end up in a map of providers, as seen in the ViewModelFacory.
#Inject
public GithubViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) { }
So we now have a GithubViewModelFactory that has a list of providers and can create any ViewModel that was bound. Fragments and Activities can now just inject the factory and retrieve their ViewModel.
#Inject
ViewModelProvider.Factory viewModelFactory;
// ...later...
repoViewModel = ViewModelProviders.of(this, viewModelFactory).get(RepoViewModel.class);
As to the why...alternatively you could create a ViewModelProvider.Factory for every Activity / Fragment and register the implementation in every Module. This would be a lot of duplicated boilerplate code, though.
In this specific example, where viewmodels are instantiated using GithubViewModelFactory is there any way to pass a parameter to the specific ViewModel? Or the better solution would be to create a setter in ViewModel and set needed param via setter?
It seems like all the ViewModels only depend on #Singleton objects—which is necessary, since they all get provided from the AppComponent. This means that there is no way to pass in "parameters" other than other #Singleton dependencies.
So, as you suggested, you'd either have to move the factory down into the Activity / Fragment component so that you can provide lower-scoped dependencies, or use a setter method.
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