Skip to main content

Dagger Multibindings saved my time



While the Android architecture made development simpler, we should always be aware of the Lifecycle and with that, the right way to provide ViewModels. Creating one ViewModel factory for each Fragment and ViewModel you have is really expensive, bad architecture, and too much unnecessary code.  Not to mention the fact that you should care about scopes, dependencies, components modules when using Dagger for DI.

You can have a simple "generic" ViewModel factory for all your app as a Singleton, with the help of Kotlin Reflection and Daggers Multibinding.

What is provided here is a class, which has a Map in the constructor and extending the ViewModelProvider.Factory. On the only method it has, we are just going to provide our own instance of the ViewModel we need, which is the key of the map, and when that dependency is available we are going to require its particular dependencies which are "stored" in the value of that map. We can place as many ViewModels as we need, and this will be achieved by Dagger Multibinding. So it's just a Map<SomeViewModels, AndSomeViewModeldependencies>. The dependencies cannot just appear directly, so with the help of Provider<T> they arrive on the moment the ViewModel has just started. The @JvmSuppressWildcards is just making sure that the explicit Provider<ViewModel> will be on the Java generated files.

To put what we need on that map, Dagger has a nice way of doing it. First, you need to create an annotation which will pass the key to the map:

For example: To access HomeViewModel dependencies, we need a key, which happens to be the class itself. After that, what is needed is just to "put" those ViewModels in the map:

Remember, we are in @Singleton scope (although in the example using a custom annotation, personal preference). So, where are the values (dependencies) for each key provided? They just appear when the ViewModel is instantiated. And that's amazing about how Dagger solves DI problem in the Java/Kotlin/Android world:

And when injecting a ViewModel factory:

Remember, all this work is not done just for a Repository, each ViewModel implementation might have different dependencies.

Conclusion:

Having tons of ViewModels in your Android app might make it too hard and expensive to produce them. When using Dagger Multibindings (if you are using dagger at all) it's a lot easier and prevents from writing bad code. Furthermore, if you want to add another Fragment and ViewModel, it's just like a game.

Popular posts from this blog

Modularizing your Android app, breaking the monolith (Part 1)

Inspired by a Martin Fowlers post about Micro Frontends, I decided to break my monolithic app into a modular app. I tried to read a little more about breaking monolithic apps in Android, and as far as I got, I felt confident to share my experience with you. This will be some series of blog posts where we actually try to break a simple app into a modularized Android app.

Note: You should know that I am no expert in this, so if there are false statements or mistakes please feel free to criticize, for the sake of a better development. 

What do you benefit from this approach:
Well, people are moving pretty fast nowadays and delivery is required faster and faster. So, in order to achieve this, modularising Android apps is really necessary.You can share features across different apps. Independent teams and less problems per each.Conditional features update.Quicker debugging and fixing.A feature delay doesn't delay the whole app. As per writing tests, there is not too much difference about…

What I learned from Kotlin Flow API

I used to check the docs and just read a lot about flows but didn't implement anything until yesterday. However, the API tasted really cool (even though some operations are still in Experimental state).Prerequisites: If you don't know RxJava it's fine. But a RxJava recognizer would read this faster.Cold vs Hot streamsWell, I really struggled with this concept because it is a little bit tricky. The main difference between cold and hot happened to be pretty simple: Hot streams produce when you don't care while in cold streams, if you don't collect() (or RxJava-s equivalent subscribe()) the stream won't be activated at all. So, Flows are what we call cold streams. Removing the subscriber will not produce data at all, making the Flows one of the most sophisticated asynchronous stream API ever (in the JVM world). I tried to make a illustration of hot and cold streams: Since I mentioned the word asynchronous this implies that they do support coroutines also. Flows vs…

From Gson to Moshi, what I learned

There is no doubt that people are getting away from GSON and I agree with those reasons too. The only advantage GSON has over other parsing libraries is that it takes a really short amount of time to set up. Furthermore, the most important thing is that Moshi is embracing Kotlin support.

First let's implement the dependency:
implementation("com.squareup.moshi:moshi:1.8.0") It's not a struggle to migrate to Moshi. It's really Gson look-a-like. The only thing to do is annotate the object with @field:Json instead of @SerializedName (which is Gsons way for JS representation):

data class User( //GSON way @SerializedName("name") val name: String, @SerializedName("user_name") val userName: String, @SerializedName("last_name") val lastName: String, @SerializedName("email") val email: String ) data class User( //Moshi way @field:Json(name = "name") val name: String, @field:Json(name = "user_name…