# Set Up Dagger with ViewModel & Saved State Module Guide

[https://www.strv.com/blog/authors/tomas](https://www.strv.com/blog/authors/tomas) Tomas Mlynaric  
Android Engineer

---

A [Android Developers](https://medium.com/u/e1f26db83092?source=post_page-----44d8fa79f14----------------------) finally [@Provide](https://twitter.com/AndroidDev/status/1187437523091378176?ref=strv.ghost.io) an opinion about dependency injection, and the winner is... **Dagger!**  
From my perspective, Dagger is “not great, not terrible." But it scales well and, when properly set up, you don't need to “touch” it later.  

In this article, I try to explain how to set up Dagger to work with ViewModel and SavedState module in the most universal way — set it once, use it forever.  

**WARNING:**  
I’m not going to get deep into Dagger, so if you don’t know the basics of how Dagger works, please check it out first. Otherwise, the article may be tricky to understand.  

**TLDR:**  
I'm sorry, this article is longer than I expected. But I wanted to explain everything with a sufficient amount of information. For those who are familiar with the details and prefer seeing working snippets only (or you're just a little lazy), skip ahead to the bottom of this page.  

Fasten your seatbelt! It's gonna be a rough ride.  

*Source: Giphy, [https://gph.is/2Lhtrua](https://gph.is/2Lhtrua)*

## THE MOTIVATION
Let's start with motivation: Why do we want to do all of this?  

Say you have a ViewModel `class SomeViewModel : ViewModel()`. Now, you want to fully use the power of ViewModels, so you apply inversion of control and pass dependencies to the constructor.  

```kotlin
class SomeViewModel(
    private val dep1: Dependency,
    private val dep2: Dependency2
) : ViewModel()
```

If you're even more demanding, you have DI framework (Dagger in our case) do this for you. I won't describe how to set up Dagger with ViewModel, as there are many articles and SO answers available (e.g. [here](https://proandroiddev.com/viewmodel-with-dagger2-architecture-components-2e06f06c9455?ref=strv.ghost.io) and [here](https://stackoverflow.com/questions/54347924/inject-property-into-viewmodel-using-dagger-2/54353028?ref=strv.ghost.io#54353028)).  

```kotlin
class SomeViewModel @Inject constructor(
    private val depFromDagger1: Dependency,
    private val depFromDagger2: Dependency2
) : ViewModel()
```

Still want more? Outrageous! Say you actually want to pass something besides dependencies coming from DI graph. Something like `Bundle`, or just some variable like `articleId`.  

What are your options?  

You can instantiate your ViewModel with dependencies from the graph and set your custom variable manually after construction with either `lateinit var` or with `var` of *nullable* type.  

```kotlin
class SomeViewModel @Inject constructor(
    private val depFromDagger2: Dependency2
) : ViewModel() {
    // may crash with UninitializedPropertyAccessException
    lateinit var articleId: String
    // must !! or ?. for every access
    var fragmentParams: Bundle? = null
}
```

Neither one of these is great because they make your code more fragile. What if you reuse your ViewModel in another screen and forget to set the dynamic parameters? Crash! ...Or an improperly initialized class. And in case of a *nullable* variable, either you force `!!` it, or you have unnecessary *null* checks in your code.  

Another option is to leave Dagger out of the game, create a custom ViewModel factory, and manually pass dependencies which will be injected into Fragment or Activity. Not great.  

```kotlin
class SomeViewModel(
    private val dep2: Dependency2,
    private val articleId: String
) : ViewModel() {
    class Factory(
        private val articleId: String
    ) : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return SomeViewModel(dep1, dep2, articleId) as T
        }
    }
}
```

In Fragment, you need to `@Inject` the dependencies and pass it to the factory.  

```kotlin
class SomeFragment : Fragment() {
    // inject into this class omitted for brevity
    @Inject lateinit var dep1: Dependency
    @Inject lateinit var dep2: Dependency
    lateinit var viewModel: SomeViewModel
    
    override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)
        // retrieve articleId and pass it to your factory
        val articleId = arguments!!.getString("article_id")
        val factory = SomeViewModel.Factory(articleId)
        viewModel = ViewModelProvider(this, factory).get(SomeViewModel::class.java)
    }
}
```

This works, but it’s so much boilerplate. With each added, changed or removed dependency, you have to update three places in your code:
- ViewModel’s constructor
- ViewModel's custom factory
- Instantiation of the factory with injected dependencies  

*(Un)fortunately, this is (probably) exactly what we want to achieve without all of the boilerplate, because we want to use one dynamically retrieved parameter — **SavedStateHandle**, from Saved State Module library.*

## VIEWMODEL AND ONSAVEINSTANCESTATE()
Before we dive into Saved State module, let's recap ViewModel's strengths and weaknesses.  

ViewModel is great at handling orientation changes, as it survives when Fragment or Activity is destroyed. This lets you keep doing any long action without leaking the screen or needing to “restart” the action.  

On the other hand, when you put your app into the background and the Android system kills it (usually due to longer inactivity and a need for more resources), the state of ViewModel is not preserved. What's worse, Fragment or Activity will handle this use case by calling `onSaveInstanceState(outState: Bundle)`, but your ViewModel has no information about it. You need to handle this yourself by taking data from ViewModel and saving it in Fragment/Activity and later restoring it by manually placing it into ViewModel. But as I showed you earlier, this makes your ViewModel less robust because you can't run actions from constructor.  

### ViewModel doesn’t handle saving/restoring state.
The truth is, many apps don’t even bother solving this issue, which leads to weird behavior or even crashing when the user opens the app after some inactivity.  

However, there's light at the end of the tunnel.  

## SAVED STATE MODULE FOR VIEWMODEL
[Saved State Module for ViewModel](https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate?ref=strv.ghost.io) is the new AndroidX library that allows handling instance state from ViewModel without any difficulty. This library provides custom factory for creating ViewModels. ViewModel constructor then expects `SavedStateHandle` parameter, which it communicates with. Destruction (and saving instance state) of a Fragment/Activity is then reflected in the handle, and ViewModel can therefore save or restore its state without the help of other classes.  

## SO HOW TO USE IT?
### 0.  
Add gradle dependency:  

```gradle
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:1.0.0-rc03"
```

### 1.  
Get the ViewModel with SavedStateViewModelFactory factory. You may also specify some default arguments to be passed into ViewModel. This parameter in the constructor is `SavedStateRegistryOwner`, which is either Fragment or Activity and serves as reference for saving/restoring the instance state.  

```kotlin
class SomeFragment : Fragment() {
    // default arguments, so you can set something dynamically
    val defaultArgs: Bundle? = bundleOf("id" to 5) // may be null
    // default factory for ViewModel creation
    val factory = SavedStateViewModelFactory(application, this, defaultArgs)
    // get the ViewModel with the factory and scope you want
    viewModel = ViewModelProvider(this, factory)[SomeViewModel::class.java]
}
```

### 2.  
In your ViewModel’s constructor, have a variable of type `SavedStateHandle`, which serves as a handler for saving or retrieving data. If you passed any default arguments, they will be part of this handle.  

```kotlin
class SomeViewModel(
    private val application: Application,
    private val savedStateHandle: SavedStateHandle
) {
    // ...
}
```

The handle has set/get methods similar to `Bundle` which, in case of ViewModel being killed by the system, are safely stored in app's state and restored later. It also has `getLiveData(key)` method, which returns `MutableLiveData` to simplify working with UI.  

In the example below, `counter` value is retrieved in ViewModel's `init {}`. If value is not set, `null` is returned. Method `onPlusClick()` changes `counter` `LiveData`. In the end, you observe the `LiveData` and set current value into the handle, which will be safely stored.  

```kotlin
class SomeViewModel(/* ..omitted.. */) {
    val counter = MutableLiveData<Int>(0)
    
    init {
        counter.value = savedStateHandle.get("counter") ?: 0
        counter.observeForever { newValue ->
            savedStateHandle.set("counter", newValue)
        }
    }
    
    fun onPlusClick() {
        counter.value = (counter.value ?: 0) + 1
    }
}
```

You can also simplify it by using `getLiveData(key, defaultValue)` method, which results in the same functionality with less code.  

```kotlin
class SomeViewModel(/* ..omitted.. */) {
    val counter = savedStateHandle.getLiveData("counter", 0)
}
```

This way, when system kills your app, you can be sure that ViewModel will save and restore its state properly without the help of Fragment/Activity class.  

## HOW TO TEST THE SYSTEM KILLING YOUR APP?
With all this information, you're probably thinking: How do I know if it actually works? You often don’t want to sit and wait until the Android system kills your app in the background; you want to test it reasonably. There are two easy options that let you simulate the behavior:  

**a. Set the background process limit to none:**  
On your device, go to *Settings* ➡ *Developer options* ➡ *Background process limit* ➡ set to **No background processes**  

or  

**b. Kill your app with adb:**  
- Put your app into background (if you don’t do this step, *adb* will kill the app anyway, but the system won’t save the instance state).  
- Use the command below to kill your package:  

```bash
#!/bin/bash
# Provide package of your application (com.example.myapp)
PACKAGE=$1
# First, put your app to background and then run this script
echo "Killing $PACKAGE"
adb shell ps | grep $PACKAGE | awk '{print $2}' | xargs adb shell run-as $PACKAGE kill
```

Alright, so — in the first section, we saw how to connect Dagger • ViewModel.  
This section described how to connect ViewModel • SavedStateHandle.  
The question now is, how do we connect all the dots? How do we use Dagger and ViewModel with SavedStateHandle?  

## DAGGER AND VIEWMODEL WITH SAVEDSTATEHANDLE
As we know now, for ViewModel we can either have a custom Factory which manually passes parameters, or fully Dagger-controlled instantiation. In our case, we would like to have a bit of both worlds.  

Let's go over what sorcery needs to be done to connect the dots.  

### @AssistedInject for the win
Unfortunately, we cannot do it without some help—a hack, so to speak. We need to introduce a way to keep injecting Dagger-related dependencies (like a `Repository` or application `Context` or something similar), while also having some of the parameters injected manually.  

See how AssistedInject works [here](https://github.com/square/AssistedInject?ref=strv.ghost.io).  

Fortunately, this is exactly what AssistedInject library does. It allows you to annotate the constructor of your class with `@AssistedInject` (in our case, ViewModel) and your dynamic parameters with `@Assisted` (in our case, SavedStateHandle). Based on this information, the library generates a Factory compatible with Dagger for instantiation of your class. The factory has an `@Inject` constructor with all dependencies from your ViewModel constructor and one method with the dynamic parameters marked with `@Assisted`.  

(You can listen to [Jake Wharton's talk](https://medium.com/u/8ddd94878165?source=post_page-----44d8fa79f14----------------------), [Helping Dagger Help You](https://jakewharton.com/helping-dagger-help-you/), where he describes it more in depth.)  

## HOW TO SET UP ASSISTEDINJECT WITH SAVEDSTATEHANDLE?
Let's start with the setup.  

### 0.  
Add gradle dependency:  

```gradle
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.2'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.2'
```

Version *0.5.2* indicates it may not be very mature, but it works fine for our use case. Since it only generates Dagger code, you shouldn’t see unstable runtime issues (worst case: some build issues).  

### 1.  
Create a *base* interface with one `create(savedStateHandle: SavedStateHandle): T` method. The generic parameter `T` serves as a hint for AssistedInject about which ViewModel type to generate. This interface helps to avoid repetitive code and is used later to add all assisted factories into a map.  

```kotlin
/**  
 * Base interface for all ViewModel factories  
 */  
interface AssistedSavedStateViewModelFactory<T : ViewModel> {  
    fun create(savedStateHandle: SavedStateHandle): T  
}
```

### 2.  
Instead of `@Inject`, use `@AssistedInject`. Mark `SavedStateHandle` parameter with `@Assisted`.  

```kotlin
class SomeViewModel @AssistedInject constructor(
    @Assisted private val savedStateHandle: SavedStateHandle
) {
    // ...
}
```

### 3.  
Inside your ViewModel class, add an interface annotated with `@AssistedInject.Factory`, extending the base interface.  

```kotlin
class SomeViewModel @AssistedInject constructor(
    // must be inside of the ViewModel class!
    @AssistedInject.Factory
    interface Factory : AssistedSavedStateViewModelFactory<SomeViewModel> {
        override fun create(savedStateHandle: SavedStateHandle): SomeViewModel
    }
}
```

AssistedInject will generate a class `SomeViewModel_AssistedFactory`, which implements this interface. It will contain Dagger-related variables (`Provider<*>`) and method `create()` from the base interface.  

*Note:* Starting with Kotlin 1.3.60, you must override the `create()` method due to a bug. More info in the [issue](https://github.com/square/AssistedInject/issues/81).  

### 4.  
Create a Dagger `@Module`, mark it with `@AssistedModule`, and include the generated module `AssistedInject_NameOfTheModule::class`.  

```kotlin
@AssistedModule
@Module(includes = [AssistedInject_BuilderModule::class])
abstract class BuilderModule {
    @Binds
    @IntoMap
    @ViewModelKey(SomeViewModel::class)
    abstract fun bindVMFactory(f: SomeViewModel.Factory): AssistedSavedStateViewModelFactory<out ViewModel>
}
```

### 5.  
Create a custom factory implementing dynamic creation. Instead of direct instantiation, create an abstract factory that can create ViewModels with dynamic parameters like `defaultArguments`. Use `AbstractSavedStateViewModelFactory` which supports passing `SavedStateHandle`.  

```kotlin
@Reusable
class InjectingSavedStateViewModelFactory @Inject constructor(
    private val assistedFactories: Map<Class<out ViewModel>, @JvmSuppressWildcards AssistedSavedStateViewModelFactory<out ViewModel>>
) {
    fun create(owner: SavedStateRegistryOwner, defaultArgs: Bundle? = null): AbstractSavedStateViewModelFactory {
        return object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
            @Suppress("UNCHECKED_CAST")
            override fun <T : ViewModel?> create(
                key: String,
                modelClass: Class<T>,
                handle: SavedStateHandle
            ): T {
                // Attempt to get ViewModel from assisted inject factories
                assistedFactories[modelClass]?.let {
                    try {
                        return it.create(handle) as T
                    } catch (e: Exception) {
                        throw RuntimeException(e)
                    }
                }
                throw IllegalArgumentException("Unknown model class $modelClass")
            }
        }
    }
}
```

### 6.  
In your Fragment, `@Inject` the factory and use it to retrieve your ViewModel.  

```kotlin
class SomeFragment : Fragment() {
    // ...
    @Inject lateinit var abstractFactory: InjectingSavedStateViewModelFactory
    lateinit var viewModel: SomeViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val defArgs = bundleOf("id" to 5) // may be null
        // create the actual factory for dagger
        val factory = abstractFactory.create(this, defArgs)
        viewModel = ViewModelProvider(this, factory)[SomeViewModel::class.java]
    }
}
```

You may also `@Inject` the factory in a base fragment to reduce boilerplate in inheriting fragments.  

## WANT TO ADD THIS TO AN EXISTING PROJECT?
This is intended for existing projects with Dagger and plain ViewModel setup, wishing to start using SavedState module. Not all ViewModels need to use SavedState in the future; you can then write less boilerplate.  

In typical Dagger + ViewModel, you'd bind your classes into a map:  
```kotlin
Map<Class<ViewModel>, Provider<ViewModel>>
```
In AssistedInject, you'll need to tweak this to:  
```kotlin
Map<Class<out ViewModel>, AssistedSavedStateViewModelFactory<out ViewModel>>
```

You can inject both maps into a *multi-purpose* factory that attempts to instantiate ViewModels via either method.  

```kotlin
@Reusable
class InjectingSavedStateViewModelFactory @Inject constructor(
    private val assistedFactories: Map<Class<out ViewModel>, @JvmSuppressWildcards AssistedSavedStateViewModelFactory<out ViewModel>>,
    private val viewModelProviders: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) {
    /**
     * Creates instance of ViewModel either annotated with @AssistedInject or @Inject and passes dependencies it needs.
     */
    fun create(owner: SavedStateRegistryOwner, defaultArgs: Bundle? = null) =
        object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
            override fun <T : ViewModel?> create(
                key: String,
                modelClass: Class<T>,
                handle: SavedStateHandle
            ): T {
                val viewModel = createAssistedInjectViewModel(modelClass, handle)
                    ?: createInjectViewModel(modelClass)
                    ?: throw IllegalArgumentException("Unknown model class $modelClass")
                return viewModel as T

                // Creates ViewModel based on @AssistedInject constructor and its factory
                private fun <T : ViewModel?> createAssistedInjectViewModel(): ViewModel? {
                    val creator = assistedFactories[modelClass]
                        ?: assistedFactories.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value
                        ?: return null
                    return creator.create(handle)
                }

                // Creates ViewModel based on regular Dagger @Inject constructor
                private fun <T : ViewModel?> createInjectViewModel(modelClass: Class<T>): ViewModel? {
                    val creator = viewModelProviders[modelClass]
                        ?: viewModelProviders.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value
                    return creator?.get()
                }
            }
        }
}
```

## TLDR
Here are the quick steps to make everything work:  

**1.** Add gradle dependency:  

```gradle
compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.2'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.2'
```

**2.** Update your ViewModel to use AssistedInject:  

```kotlin
class SomeViewModel @AssistedInject constructor(
    // ...
)
```

**3.** Create or update your Dagger module with `@AssistedModule`, include generated module, and bind ViewModel factories:  

```kotlin
@AssistedModule
@Module(includes = [AssistedInject_BuilderModule::class])
abstract class BuilderModule {
    abstract fun bindVMFactory(f: SomeViewModel.Factory): AssistedSavedStateViewModelFactory<out ViewModel>
}
```

**4.** Create or update your ViewModel factory, similar to `InjectingSavedStateViewModelFactory.kt` [see gist](https://gist.github.com/mlykotom/c2b528e1f9a2ca1039ad5e992308ccb2?ref=strv.ghost.io).  

**5.** Retrieve your ViewModel via the factory in your Fragment:  

```kotlin
class SomeFragment : Fragment() {
    // ...
    lateinit var viewModel: SomeViewModel
    @Inject lateinit var factory: InjectingSavedStateViewModelFactory

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val defArgs = bundleOf("id" to 5)
        viewModel = ViewModelProvider(this, factory.create(this, defArgs))[SomeViewModel::class.java]
    }
}
```

## CONCLUSION
In this article, I covered how to set up Dagger with ViewModels and Saved State module in a boilerplate-efficient manner. The initial setup is tedious, but future ViewModels require minimal boilerplate.  

You can adapt your existing project without full rewrite, and there's a sample project [here](https://github.com/mlykotom/connecting-the-dots-sample) with examples of `@Inject` and `@AssistedInject` ViewModels.  

## REFERENCES
The articles below inspired this guide. Connecting them is the tricky part:  
- [Saving UI state with ViewModel, SavedState, and Dagger](https://proandroiddev.com/saving-ui-state-with-viewmodel-savedstate-and-dagger-f77bcaeb8b08?ref=strv.ghost.io)  
- [Brave new Android with AssistedInject](https://proandroiddev.com/brave-new-android-world-with-assistedinject-d11bdc20147d?ref=strv.ghost.io)  
- [How to produce SavedStateHandle with CoroutineDispatcher](https://www.coroutinedispatcher.com/2019/08/how-to-produce-savedstatehandle-in-your.html?ref=strv.ghost.io)  

Thanks to everyone who reviewed this article, especially [Marek Abaffy](https://medium.com/u/2648e51c9617?source=post_page-----44d8fa79f14----------------------), [Michal Urbanek](https://medium.com/u/29a315899171?source=post_page-----44d8fa79f14----------------------), and [Iveta Jurčíková](https://medium.com/u/177a4c6dcd67?source=post_page-----44d8fa79f14----------------------).