I have a little problem with designing DI architecture of my app. I am using Architecture Components ViewModels and I was inspired how to provide ViewModels via Dagger in their own GitHub repository .. I want to create scoped component/module for example for product detail that would provide ViewModels/Repositories and other stuff dependent on that single product.. problem is that all ViewModels are provided from the same ViewModelModule as in given example. But ProductViewModel needs ProductRepository that is provided from scoped subcomponent ProductModule. And apparently thats not possible because Dagger throws error at build time that I need to provide ProductRepository with #Provides annotation.
Ok so I thought that I would provide ProductViewModel in my ProductModule but then it crashes at runtime, because provider of my ViewModel can't be found in this method
Is it possible at all to have this architecture or do I need to redesign it to not use the same method as Google in their sample?
I was able to solve a similar problem by removing the #Singleton annotation on the ViewModelProvider.Factory subclass.
It shouldn't matter whether the factory is a singleton or not; it's only a performance issue, really. I ended up using #Reusable instead, which tells Dagger that the factory instance can be safely reused if needed, but without the restrictions of a specific scope.
Related
I have been using Dagger for a while and now I'm starting to migrate to Hilt, but I don't understand the benefits of injecting Activity and Fragment.
In Dagger, it is AndroidInjection.inject(this) and something like HasActivityInjector
Sorry if it was a stupid question.
It is not a benefit, it is a constraint imposed by Android. Activities and Fragments are instantiated by Android, not by the developer or the DI framework, and as such, they require special treatment. It is the same in Dagger actually.
In Hilt you don't need to write that code manually anymore, you can just annotate the Application, Activity and Fragment using special notations, the library will take care of generating the corresponding code.
I saw this question, but it was from the point of testability.
In my case, I see Dagger as an additional complexity for code (create #Provides methods, inject methods, remember all the right annotations). Should I still use Dagger if I just want to inject singletons like SharedPrefUtils? Is it really faster for this case?
Dagger was not made for creating Singletons and if creating a singleton is the reason you want to add Dagger to your project, then its an overkill. Dagger is a dependency injection framework that helps make the process of providing and injecting dependencies easier in a complex project. The #Singleton would help you ensure that only a single instance of a class is created when satisfying your dependencies it is not an alternative to the Kotlin object, they could even be used together. So like other answers and comments suggest if you have a small project and you could use simple design patterns like Singleton, Factory, and Abstract factory pattern.
Dagger is a dependency injection framework. For very simple applications, you can go with manual injection which will save you time because dagger can be difficult to set up and work with from the beginning. However, if you are planning on a production application which has a very long life span and will contain multiple UIs and multiple classes, then you are definitely going to need a dependency injection framework or strategy along the line.
There is an alternative for Kotlin which is Koin. Koin works more like a Service Locator and is easier to set up than Dagger but I will prefer dagger because it has survived the test of time.
It is up to you whether you want to use automatic dependency injection or manual injection so in the end you weigh your options and see what best fits your use case.
So I've got this scenario in Android where I have AppComponent, which is a #Singleton. One of my modules, which needs to have a custom scope, #ActivityScope I'm calling it, provides an object which it instantiates and whose constructor requires another object which is provided by AppModule. This is a problem, because when I try to reference AppModule from this module I get an error because one is scoped as #Singleton and the other one as #ActivityScope.
I'm having trouble trying to apply what I read online about subcomponents, which seem the way to go, to my particular case. Can I get any hint?
I'm exploring the new Android Architecture Components and looking to implement it into an Android app. I am firmillair with MVVM as I use the paradigm on iOS development. Having read through the Android Architecture Components guide, provided by Google: https://developer.android.com/topic/libraries/architecture/guide.html
I have just a few questions...
In the above mentioned guide, Google use the UserRepository class that access these web service API - they go on to make this class a Singleton which is probably fine, if there were only ever one screen on the app that needed data from a REST API.
My concern, is this; it seems Google advocate the need to create a repository class on a per-ViewModel basis. This sounds very wrong to me, in having so many Singlton classes in the app. If we were to have 10 screens, with ten ViewModels - each needing its own Repository module - we then have ten singletons in our app. From an iOS dev perspective, this is wrong to have so many.
The solution to this, would be to have one mediator (Repository) class, that has public methods, exposing the API to get data from a REST API. The Web service part, would be in its own class. That way, we have a decent separation of concerns.
Is it best practice, to have one repository class, per, ViewModel - or to have one per app? I'm not 100% sure on this.
Lastly, I have the same concern when it comes to Room- is Google saying we create a DB on a per ViewModel bases or just one DB per app?
I don't think the architecture guide suggests to create a separate repository class for each ViewModel. In the example that is shown Google uses a library called Dagger to inject the singleton repository class into the ViewModel. It is normally best practice to split repositories (or managers) on functionality. UserRepository is responsible for all user related api calls for example.
If you turn this repository into a singleton that you can inject in any ViewModel, any ViewModel now has access to that specific repository.
After quickly looking into Room I found this little snippet (link):
Note: You should follow the singleton design pattern when instantiating an AppDatabase object, as each RoomDatabase instance is fairly expensive, and you rarely need access to multiple instances.
This to me means that you can implement the RoomDatabase much in the same way you can use your repository classes. Simply inject them as a singleton into your ViewModel so you don't need to have multiple instances of the same database.
When using Dagger, I found that I'm getting multiple instances of a singleton when I inject it wherever I need it. I've annotated the class and the provides method with #Singleton. Can anyone think of why this is happening?
Edit:
If it helps, I have followed the same structure for my app as the sample application in Dagger's GitHub (https://github.com/square/dagger/tree/master/examples/android-activity-graphs). I'm trying to get the Singleton in the base activity and a couple of third party classes provided using #Provides at the custom Application class. Is it because I'm plus-ing modules at each activity to the original object graph?
(PS : I'm new to Dagger and DI in general, so I'll be grateful if you could provide an explanation so that I may learn. Thanks.)
#Singleton, in Dagger 1.x, acts differently than you might think. The JSR-330 spec definition in the #Singleton javadoc is "one per graph" and that is how Dagger interprets it.
So if you have something that is marked as #Singleton, and it is materialized in your application graph (as opposed to a shorter-lifetime graph), then you get one instance per application.
If you have an item annotated #Singleton that's in the modules you use to configure your activity graph (i.e., that is obtained from the part of a graph specified by a module used in the plus() operation) then you will get one-per-activity-graph.
If you need something to be once-per-application, you need to make sure it gets created as a part of the application graph. You can do this in one of two ways. Either explicitly provide it with an #Provides method from your application module(s), or you can list it as a one of the classes in #Module(injects=...) in an application module.
(If you do not mark it with #Singleton than you will get one per injection site.)
So remember, the graph created by plus() is seen as a separate graph that points to the graph from which it was spawned, and wraps it, can access instances within it, but is not the same graph.
Note - Dagger 2.x improves this, and supports custom scoping annotations, though the mechanism is similar, with one graph (component) per scope annotation, with a parent/child relationship between graphs of wider/narrower lifetimes