Skip to content

Manual Dependency Injection

When creating a simple app making use of the AbstractSavedStateViewModelFactory to manually inject dependencies, this section showcases a sample using that.

ViewModel

A paired down version of the ViewModel for this sample is shown below:

class MainViewModel(
    savedStateFlowHandle: SavedStateFlowHandle,
    private val newsDataSource: NewsDataSource
) : ViewModel() {

    private val query: SavedStateFlow<String> =
        savedStateFlowHandle.getSavedStateFlow(viewModelScope, "main-viewmodel-query-key", "")

    init {
        observeQuery()
    }

    fun updateQuery(query: String) {
        this.query.value = query
    }

    private fun observeQuery() {
        viewModelScope.launch {
            query.asStateFlow()
                .flatMapLatest { query ->
                    newsDataSource.fetchQuery(query)
                }
                .collect { results ->
                    //TODO update state 
                }
        }
    }

}

The full version of this ViewModel can be found here.

ViewModel Factory

Now to actually create an instance of the ViewModel and provide it an instance of SavedStateFlowHandle, create a factory class that extends AbstractSavedStateViewModelFactory and make use of the extension function SavedStateHandle.toSavedStateFlowHandle().

class MainViewModelFactory(
    owner: SavedStateRegistryOwner,
    defaultArgs: Bundle? = null
) : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
    override fun <T : ViewModel?> create(
        key: String,
        modelClass: Class<T>,
        handle: SavedStateHandle
    ): T {
        return MainViewModel(handle.toSavedStateFlowHandle(), NewsRepository) as T
    }
}

Grabbing a Reference to ViewModel

Finally an instance of a ViewModel can be grabbed from the view using the by viewmodels { } delegation function and passing it an instance of the factory.

class MainActivity : ComponentActivity() {
    private val viewModel: MainViewModel by viewModels {
        MainViewModelFactory(this)
    }
}

Resources

Suggestion

Manual dependency injection is great for small apps and for understanding the basic concept, however it can lead to writing a lot of boiler plate code creating ViewModel factory classes. To help reduce the amount of boiler plate, you can move onto the next section to see how a dependency injection framework like Hilt can be used with SavedStateFlow.