Loading...
Home
  • Tech Blogs
  • Videos
  • Conferences
    • Droidcon News
    • Upcoming Conferences
    • Become a Partner
    • Past Events
    • Keep Me Informed
    • Diversity Scholarships
  • Community
    • droidcon Team
    • How to Hold a Droidcon
  • Android Careers
Sign In

Global CSS

 

ViewModel by Dependency Injection: from Dagger to Hilt

 

 
GuilhE
🇵🇹 https://github.com/GuilhE
Published: July 13, 2020
Tweet
Share
 
 

Photo by Markus Spiske on Unsplash

 

I assume the reader has knowledge and strong base concepts of Kotlin, Dagger, and Android App Architecture.


Intro

The purpose of this article is to show an Activity evolution — can also be applied to a Fragment — to accommodate a ViewModel setup. Throughout this journey we’ll see how dependency injection will fit in by using the following approaches:

  • Dagger (Vanilla Dagger)
  • Dagger Android
  • Hilt

This will not teach how to use Dagger nor Hilt, instead, it will show the setup I found useful — on each approach — to provide ViewModels with their dependencies, SavedStateHandle and intent.extras. I’ll add all the references that helped me achieve this goals as a final chapter. From them, you can learn and understand what’s happening behind the curtains.


Before we start

For both Dagger approaches, Activity : DaggerAppCompatActivity()and/or Fragment : DaggerFragment() .

Regarding Application class:

 

 


Dagger, the Simple 🗡️

This setup is quite simple and involves less boilerplate code, for it we’ll need:

AppComponent.kt

 

 

AppModule.kt

 

 

ActivityBindingModule.kt

 

 

note: for every activity we need a new entry in this class.

MyActivityModule.kt

 

 

BaseActivityModule.kt

 

 

And the setup it’s done, to create and retrieve a ViewModel we simply:

 

 

Conclusion

  • Except for SavedStateHandle, all ViewModel dependencies will have to be field injected or externally set;
  • For each new Activity, a respective [x]ActivityModule.kt class will have to be created and a new entry added to ActivityBindingModule.kt;
  • No ViewModelFactory code was needed.

 

Dagger Android, the Complex ⚔️

This approach is more verbose and complex thanks to the ViewModelFactorylogic that will have to be created and managed. Fortunately we can benefit from code generation tools and — in my opinion — this is where we take the most from a “Dagger setup template”. After we understand what’s happening we just have to take care of the manual boilerplate.

Let’s see how the classes earlier created will change and how many will be added.

First we create an AssistedModule.kt

 

 

and add it to AppModule.kt

 

 

Our [x]ActivityModule.kt classes will also include this AssistedModule and the Factory setup:

 

 

Next, lets move on to Factories.


Factories

  • ViewModelAssistedFactory: will help us with the SavedStateHandle logic;
  • ViewModelFactoryByInjection: it will be our “auto-factory”;
  • ViewModelFactory: it will be our “manual-factory”.

note: usually I go with ViewModelFactoryByInjection but I think it’s useful to show how to use the ViewModelFactory. Latter you’ll see how the setup can work with both.

ViewModelAssistedFactory.kt

 

 

ViewModelFactoryByInjection.kt

 

 

ViewModelFactory.kt

 

 


Back to our setup, let’s finish it.

ViewModels now will have the SaveStateHandle assisted injected, thus Inject will change to AssistedInject and Assistedwill be added. Remaining dependencies will be constructor injected. Finally, we add the Factory interface:

 

 

Our Activity

 

 

And there you go, our ViewModel creation it’s done. Let’s see what would have changed in our Activity if we used ViewModelFactory instead:

 

 

Simple right?

 

Conclusion

  • New module created;
  • For each new Activity, a respective [x]ActivityModule.kt class will have to be created and a new entry added to ActivityBindingModule.kt. The[x]ActivityModule.kt is more verbose since now we have to add the Factory Bind setup;
  • All ViewModel dependencies are constructor injected, and the Factoryinterface needs to be added;
  • ViewModelFactory classes created;
  • Activity needs to inject the Factory before creating its ViewModel.

 

Bonus

Before we jump into Hilt, let’s create a BaseActivity so it can accommodate all Dagger approaches:

Dagger & AndroidDagger

 

 

Our Activity (Dagger) becomes:

 

 

Our Activity (DaggerAndroid) becomes:

 

 

Pretty cool right? 😎

 

Hilt, the Illusionist 🔮

Because Hilt will be using Dagger under the hood all the previous setup will be simplified, in fact, we’ll delete almost all classes 😆.

Application.kt will be simplified into:

 

 

As you can see, HiltAndroidApp annotation replaces AndroidInjector code. They’re both responsible for starting the dependency graph generation.

Yet replaces is not the best word, hides should be used instead, but why? Well, Hilt annotations will generate Hilt_MyClassName.java classes, those classes will contain all the code that we previously had to configure ourselves. After a successful build we’ll have a Hilt_MyApp.java and so on.

Next we have AndroidEntryPoint which works just like HiltAndroidApp.

Activity.kt (without BaseActivity.kt) will be simplified into:

 

 

Activity.kt (with BaseActivity.kt) will be simplified into:

 

 

BaseActivity.kt will be simplified into:

 

 

Hilt will generate something like:

 

 

Next we have ViewModelInject which replaces Inject. This one wont generate code, instead, it’ll enable constructor injection in our ViewModels.

ViewModel.kt will be simplified into:

 

 

Closer look into dependencies

Let’s take a closer look on how our dependencies are being provided. First we create an AppProviders module and finish it by adding InstallInannotation:

 

 

And that’s it. Now, if we put a breakpoint in ViewModelProvider(this).get(getViewModelClass(), when follow the call chain, we’ll see:

ViewModelProvider.kt (get() line 170, line 185)> AbstractSavedStateViewModelFactory.kt (create() line 66, line 69) > HiltViewModelFactory.kt (create() line 62) > DaggerMyApp_HiltComponents_ApplicationC.kt (get()) > ActivityCImpl.this.getMyActivityViewModel_AssistedFactory()

which contains the dependencies generated by Hilt, example:

 

 

So that’s why, AppComponent.kt, AppModule.kt, AssistedModule.kt, ActivityBindingModule.kt, ViewModelAssistedFactory.kt, ViewModelFactoryByInjection.kt can be deleted 🥳.

 

Intent.extras

Regarding intent extras provided in runtime by our factories, you may ask. Well, again, Hilt automagically (shown above) injects them inside SavedStateHandle for us, thus, we only have to:

 


Final Thoughts

Hilt works mainly based on annotations and code generation, that’s why it looks so easy and appealing. Can be seen as a helper layer between the developer and Dagger powerful tools.

By the time I’m writing this article, Hilt version is still in alpha so, personally, until it becomes more stable (at least for production projects), I’ll stick with the Dagger Android approach. Nevertheless, migrating to Hilt was super simple and I ended up with a killer setup! 🤩

Can this be a step closer to a simpler Dependency Injection framework with an easier learning curve? I believe it will, let’s see how it evolves.

I hope you find this article useful, thanks for reading.


References

  • Elye: Comparing Dagger 2, Koin and Service Locator approaches
  • Tomáš Mlynarič: Connecting The Dots
  • David Liu: AssistedInject and AssistedModules - PR, issue
  • Manuel Vivo: Dependency Injection on Android with Hilt
  • Dagger and Hilt docs

 

 

 

Tags: Dagger, Dagger 2, Dagger Hilt, Viewmodel, Android

 

View original article at: 


 

Originally published: June 15, 2020

Android News
Evolution of Android Update SystemEvolution of Android Update System
Evolution of Android Update SystemEvolution of Android Update System

By Ivan Kuten

So, how can you update Android on mobile devices? While developing software for Smart TVs and Android-based set-top boxes, we’ve narrowed it down to four ways, discarding some very exotic options:

By ProAndroidDev -
Android News
Happy Railway
Happy Railway

By Hadi Lashkari Ghouchani

This post is on the tail of Railway Oriented Programming in Kotlin by Antony Harfield. So you need to read it first and continue here. As it’s obvious I really liked it and tried it out. It needs every process have a result like

By ProAndroidDev -
Android News
Unit Tests and Concurrency
Unit Tests and Concurrency

By Stojan Anastasov

Once Retrofit added RxJava support, RxJava became my go-to concurrency framework for writing Android apps. One of the great things about RxJava is the excellent testing support. It includes TestObserver, TestScheduler, RxJavaPlugins so you can switch your schedulers in tests.

By ProAndroidDev -
Android News
When Compat libraries will not save you
When Compat libraries will not save you

By Danny Preussler

And why you should avoid using the “NewApi” suppression! The idea of “Compat” libraries was probably one of the key aspects of Android dominating the mobile space. Other than with iOS, Android users often could not update their operating system after a new version launch, simply as their phones won’t allow them to, the Android problem of fragmentation.

 

By ProAndroidDev -
droidcon News

Tech Showcases,

Developer Resources &

Partners

/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/home-details/EmployerBrandingHeader
EmployerBrandingHeader
https://jobs.droidcon.com/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/jobs-droidcon/jobs.droidcon.com
jobs.droidcon.com

Latest Android Jobs

http://www.kotlinweekly.net/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/kotlin-weekly/Kotlin Weekly
Kotlin Weekly

Your weekly dose of Kotlin

https://proandroiddev.com/
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/pad/ProAndroidDev
ProAndroidDev

Android Tech Blogs, Case Studies and Step-by-Step Coding

/detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando
Zalando

Meet one of Berlin's top employers

/detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success
/portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success
Academy for App Success

Google Play resources tailored for the global droidcon community

Follow us

Team droidcon

Get in touch with us

Write us an Email

 

 

Quicklinks

> Code of Conduct

> Terms and Conditions

> How to hold a conference

> FAQs

> Imprint

Droidcon is a registered trademark of Mobile Seasons GmbH Copyright © 2020. All rights reserved.

powered by Breakpoint One