Skip to content

Instantly share code, notes, and snippets.

@Zhuinden
Last active September 11, 2021 06:25
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Zhuinden/06b86cb35cba0cb5e880505042e18c3d to your computer and use it in GitHub Desktop.
Save Zhuinden/06b86cb35cba0cb5e880505042e18c3d to your computer and use it in GitHub Desktop.
Dagger + ViewModel + SavedStateHandle
@Singleton
@Component(modules = [AssistedInjectionModule::class])
interface ApplicationComponent {
fun mySavedStateViewModelFactory(): MySavedStateViewModel.Factory
}
@AssistedModule
@Module(includes = {AssistedInject_AssistedInjectionModule.class})
public class AssistedInjectionModule {
}
import androidx.lifecycle.observe
class MySavedStateFragment : Fragment(R.layout.my_saved_state_fragment) {
private val viewModel by navGraphSavedStateViewModels(R.id.registration_graph) { handle ->
Injector.get().mySavedStateViewModelFactory().create(handle)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val binding = MySavedStateFragmentBinding.bind(view)
viewModel.blah.observe(viewLifecycleOwner) { blah ->
// ...
}
}
}
class MySavedStateViewModel @AssistedInject constructor(
private val authenticationManager: AuthenticationManager,
@Assisted private val savedStateHandle: SavedStateHandle
) : ViewModel() {
@AssistedInject.Factory
interface Factory {
fun create(savedStateHandle: SavedStateHandle): MySavedStateViewModel
}
}
inline fun <reified T : ViewModel> SavedStateRegistryOwner.createAbstractSavedStateViewModelFactory(
arguments: Bundle,
crossinline creator: (SavedStateHandle) -> T
): ViewModelProvider.Factory {
return object : AbstractSavedStateViewModelFactory(this, arguments) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(
key: String, modelClass: Class<T>, handle: SavedStateHandle
): T = creator(handle) as T
}
}
inline fun <reified T : ViewModel> Fragment.navGraphSavedStateViewModels(
@IdRes navGraphId: Int,
crossinline creator: (SavedStateHandle) -> T
): Lazy<T> {
// Wrapped in lazy to not search the NavController each time we want the backStackEntry
val backStackEntry by lazy { findNavController().getBackStackEntry(navGraphId) }
return createViewModelLazy(T::class, storeProducer = {
backStackEntry.viewModelStore
}, factoryProducer = {
backStackEntry.createAbstractSavedStateViewModelFactory(
arguments = backStackEntry.arguments ?: Bundle(), creator = creator
)
})
}
inline fun <reified T : ViewModel> Fragment.fragmentSavedStateViewModels(
crossinline creator: (SavedStateHandle) -> T
): Lazy<T> {
return createViewModelLazy(T::class, storeProducer = {
viewModelStore
}, factoryProducer = {
createAbstractSavedStateViewModelFactory(arguments ?: Bundle(), creator)
})
}
@adam-hurwitz
Copy link

adam-hurwitz commented Jul 19, 2020

I created a fork and added documentation to ViewModelUtils.kt as well as helper functions to manually inject CoroutineScope and a DispatcherProvider for Kotlin Coroutines in production and testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment