# Set Up Dagger with ViewModel & Saved State Module Guide

[![Tomas Mlynaric](https://www.strv.com/blog/authors/tomas)](https://www.strv.com/blog/authors/tomas)  
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 want to pass something besides dependencies coming from the DI graph. Like a `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 a `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, you either force `!!` or have unnecessary null checks.

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

```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() {
  // dependencies 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:
- ViewModel’s constructor  
- ViewModel's custom factory  
- Instantiation of the factory with injected dependencies

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

---

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

- **Strength:** ViewModel handles orientation changes, surviving when Fragment or Activity is destroyed, so you can keep long actions running without leaks or restarts.
- **Weakness:** When the app goes into background and is killed by the system (due to inactivity or resource needs), ViewModel's state isn't preserved. Fragment or Activity calls `onSaveInstanceState(outState: Bundle)` but ViewModel has no info about it. You must manually save data from ViewModel and restore it, which makes ViewModel less robust.

### ViewModel doesn’t handle saving/restoring state.

Many apps skip solving this, leading to weird behavior or crashes after inactivity.

But there’s hope.

---

## 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 handles instance state seamlessly. It provides a custom factory for creating ViewModels with a `SavedStateHandle` parameter, which syncs with the lifecycle. When the Fragment/Activity is destroyed or recreated, the handle is updated, and the ViewModel can save/restore state without extra 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`
```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
  viewModel = ViewModelProvider(this, factory)[SomeViewModel::class.java]
}
```

### 2. In your ViewModel’s constructor, have a variable of type `SavedStateHandle`
```kotlin
class SomeViewModel(
  private val application: Application,
  private val savedStateHandle: SavedStateHandle
) {
  // ...
}
```
The handle acts like a `Bundle`. It’s safe to store data that survives process death. It offers `get()`, `set()`, and `getLiveData()` for UI.

Usage example:
```kotlin
class SomeViewModel(/* ... */) {
  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
  }
}
```
Or more concise:
```kotlin
class SomeViewModel(/* ... */) {
  val counter = savedStateHandle.getLiveData("counter", 0)
}
```
Saving/restoring state is automatic on process death, no fragment needed.

---

## HOW TO TEST THE SYSTEM KILLING YOUR APP?
- **a. Limit background processes:**  
Settings > Developer options > Background process limit > No background processes
- **b. Kill app with adb:**  
```bash
#!/bin/bash
# Usage: ./kill_app.sh com.example.myapp
PACKAGE=$1
echo "Killing $PACKAGE"
adb shell ps | grep $PACKAGE | awk '{print $2}' | xargs adb shell run-as $PACKAGE kill
```

---

## DAGGER AND VIEWMODEL WITH SAVEDSTATEHANDLE
We have two configurations:
- Custom Factory passing parameters manually
- Fully Dagger-controlled instantiation

To combine both, we use `@AssistedInject`.

### @AssistedInject for the win
You need to inject Dagger dependencies and dynamic parameters (`SavedStateHandle`) together. See [here](https://github.com/square/AssistedInject).

`@AssistedInject` annotates constructor; parameters marked `@Assisted` are supplied at runtime. The library generates a Dagger-compatible Factory.

[Helping Dagger Help You](https://jakewharton.com/helping-dagger-help-you/)

---

## HOW TO SET UP ASSISTEDINJECT WITH SAVEDSTATEHANDLE?
### 0. Add dependencies
```gradle
compileOnly "com.squareup.inject:assisted-inject-annotations-dagger2:0.5.2"
kapt "com.squareup.inject:assisted-inject-processor-dagger2:0.5.2"
```

### 1. Create base interface
```kotlin
interface AssistedSavedStateViewModelFactory<T : ViewModel> {
  fun create(savedStateHandle: SavedStateHandle): T
}
```

### 2. Use `@AssistedInject` and annotate `SavedStateHandle` with `@Assisted`:
```kotlin
class SomeViewModel @AssistedInject constructor(
  @Assisted private val savedStateHandle: SavedStateHandle
) {
  // ...
}
```

### 3. Inside ViewModel, define factory interface:
```kotlin
class SomeViewModel @AssistedInject constructor(
  @AssistedInject.Factory
  interface Factory : AssistedSavedStateViewModelFactory<SomeViewModel> {
    override fun create(savedStateHandle: SavedStateHandle): SomeViewModel
  }
}
```

`AssistedInject` generates `SomeViewModel_AssistedFactory`. It has Dagger variables and implements `create()`.

Note: For Kotlin 1.3.60+, override `create()` due to a bug.

### 4. Create a Dagger `@Module` with `@AssistedModule`
```kotlin
@AssistedModule
@Module(includes = [AssistedInject_BuilderModule::class])
abstract class BuilderModule {
  @Binds
  @IntoMap
  @ViewModelKey(SomeViewModel::class)
  abstract fun bindVMFactory(f: SomeViewModel.Factory): AssistedSavedStateViewModelFactory<out ViewModel>
}
```
Generate the module by building twice.

### 5. Use a custom factory (`InjectingSavedStateViewModelFactory`) to create ViewModels:
```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 {
        val creator = assistedFactories[modelClass]
          ?: assistedFactories.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value
          ?: throw IllegalArgumentException("Unknown model class $modelClass")
        return creator.create(handle) as T
      }
    }
  }
}
```

### 6. In your Fragment, inject the factory and create ViewModel:
```kotlin
class SomeFragment : Fragment() {
  lateinit var abstractFactory: InjectingSavedStateViewModelFactory
  lateinit var viewModel: SomeViewModel

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val defArgs = bundleOf("id" to 5)
    val factory = abstractFactory.create(this, defArgs)
  }
}
```

---

## WANT TO ADD THIS TO AN EXISTING PROJECT?
For projects already using Dagger with “plain” ViewModels, you can start using SavedState module with less boilerplate:
- Instead of a map of `Provider<ViewModel>`, use `AssistedSavedStateViewModelFactory`.
- Inject both maps:
```kotlin
Map<Class<out ViewModel>, @JvmSuppressWildcards AssistedSavedStateViewModelFactory<out ViewModel>>
```

Replace your ViewModel creation to attempt both approaches, fallback on crash if unknown.

```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>>
) {
  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
    }

    private fun <T : ViewModel?> createAssistedInjectViewModel(
      modelClass: Class<T>, handle: SavedStateHandle
    ): ViewModel? {
      val creator = assistedFactories[modelClass]
        ?: assistedFactories.asIterable().firstOrNull { modelClass.isAssignableFrom(it.key) }?.value
        ?: return null
      return creator.create(handle)
    }

    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 essential steps:

1. Add dependencies:
```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:
```kotlin
class SomeViewModel @AssistedInject constructor(
  @Assisted private val savedStateHandle: SavedStateHandle
) { /*...*/ }
```

3. Create or update your Dagger module:
```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 (see [gist](https://gist.github.com/mlykotom/c2b528e1f9a2ca1039ad5e992308ccb2?ref=strv.ghost.io)).

5. Retrieve ViewModel with the factory.

---

## CONCLUSION
In this guide, I showed how to set up Dagger with ViewModels and Saved State module with minimal boilerplate. The first setup is boilerplate-heavy, but subsequent ViewModels become straightforward. It’s possible to adapt existing projects to use this setup without rewriting everything.

Sample project with one Activity, Fragment, and two ViewModels (one with `@Inject`, one with `@AssistedInject`) is [here](https://github.com/mlykotom/connecting-the-dots-sample?ref=strv.ghost.io).

---

## REFERENCES
These articles led me here, each describes one “dot”:  
- [Saving UI state with ViewModel + SavedState + Dagger](https://proandroiddev.com/saving-ui-state-with-viewmodel-savedstate-and-dagger-f77bcaeb8b08?ref=strv.ghost.io)  
- [Brave new Android world with AssistedInject](https://proandroiddev.com/brave-new-android-world-with-assistedinject-d11bdc20147d?ref=strv.ghost.io)  
- [How to produce SavedStateHandle](https://www.coroutinedispatcher.com/2019/08/how-to-produce-savedstatehandle-in-your.html?ref=strv.ghost.io)

Thank you 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----------------------).

---

*Don't miss anything.*