Last active
August 6, 2021 13:47
-
-
Save marcellogalhardo/a8db9827d8d3d8be4ded568d1b286093 to your computer and use it in GitHub Desktop.
A ViewModel that supports assisted injection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package dev.marcellogalhardo.viewmodel | |
import android.os.Bundle | |
import androidx.activity.ComponentActivity | |
import androidx.activity.viewModels | |
import androidx.core.os.bundleOf | |
import androidx.fragment.app.Fragment | |
import androidx.fragment.app.activityViewModels | |
import androidx.fragment.app.viewModels | |
import androidx.lifecycle.AbstractSavedStateViewModelFactory | |
import androidx.lifecycle.SavedStateHandle | |
import androidx.lifecycle.ViewModel | |
import androidx.lifecycle.ViewModelProvider | |
import androidx.savedstate.SavedStateRegistryOwner | |
import kotlin.reflect.KClass | |
private typealias ViewModelInstantiate<VM> = (AssistedViewModelContext) -> VM | |
/** | |
* An utility function that creates generic a [ViewModelProvider.Factory] connected to the [SavedStateRegistryOwner], | |
* where [instantiate] can be used to create a [ViewModel] using Assisted Injection. | |
* | |
* @see [Assisted Injection](https://dagger.dev/dev-guide/assisted-injection.html) | |
*/ | |
@Suppress("FunctionName") | |
fun <VM : ViewModel> AssistedViewModelFactory( | |
owner: SavedStateRegistryOwner, | |
defaultArgs: Bundle?, | |
instantiate: ViewModelInstantiate<VM>, | |
): ViewModelProvider.Factory { | |
return object : AbstractSavedStateViewModelFactory(owner, defaultArgs) { | |
@Suppress("UNCHECKED_CAST") | |
override fun <T : ViewModel> create( | |
key: String, | |
modelClass: Class<T>, | |
handle: SavedStateHandle | |
): T { | |
val context = AssistedViewModelContext(key, modelClass.kotlin, handle) | |
return instantiate(context) as T | |
} | |
} | |
} | |
/** | |
* @see AssistedViewModelFactory | |
*/ | |
@Suppress("FunctionName") | |
fun <VM : ViewModel> AssistedViewModelFactory( | |
activity: ComponentActivity, | |
instantiate: ViewModelInstantiate<VM>, | |
): ViewModelProvider.Factory = AssistedViewModelFactory( | |
owner = activity, | |
defaultArgs = activity.intent?.extras ?: bundleOf(), | |
instantiate = instantiate, | |
) | |
/** | |
* @see AssistedViewModelFactory | |
*/ | |
@Suppress("FunctionName") | |
fun <VM : ViewModel> AssistedViewModelFactory( | |
fragment: Fragment, | |
instantiate: ViewModelInstantiate<VM>, | |
): ViewModelProvider.Factory = AssistedViewModelFactory( | |
owner = fragment, | |
defaultArgs = fragment.arguments, | |
instantiate = instantiate, | |
) | |
data class AssistedViewModelContext internal constructor( | |
val key: String, | |
val modelClass: KClass<out ViewModel>, | |
val handle: SavedStateHandle, | |
) | |
/** | |
* Like [ComponentActivity.viewModels] but allowing assisted injection on the | |
* created view model. For convenience, [viewModelProducer] has access to a | |
* [SavedStateHandle] to handling process death. | |
* | |
* @see [ComponentActivity.viewModels] | |
*/ | |
inline fun <reified VM : ViewModel> ComponentActivity.assistedViewModels( | |
noinline defaultArgs: () -> Bundle? = { intent?.extras }, | |
noinline instantiate: ViewModelInstantiate<VM>, | |
): Lazy<VM> = viewModels { | |
AssistedViewModelFactory(owner = this, defaultArgs(), instantiate) | |
} | |
/** | |
* Like [Fragment.viewModels] but allowing assisted injection on the | |
* created view model. For convenience, [viewModelProducer] has access to a | |
* [SavedStateHandle] to handling process death. | |
* | |
* @see [Fragment.viewModels] | |
*/ | |
inline fun <reified VM : ViewModel> Fragment.assistedViewModels( | |
noinline owner: () -> Fragment = { this }, | |
noinline defaultArgs: () -> Bundle? = { owner().arguments }, | |
noinline instantiate: ViewModelInstantiate<VM>, | |
): Lazy<VM> = viewModels(ownerProducer = { owner() }) { | |
AssistedViewModelFactory(owner(), defaultArgs(), instantiate) | |
} | |
/** | |
* Like [Fragment.activityViewModels] but allowing assisted injection on the | |
* created view model. For convenience, [viewModelProducer] has access to a | |
* [SavedStateHandle] to handling process death. | |
* | |
* @see [Fragment.activityViewModels] | |
*/ | |
inline fun <reified VM : ViewModel> Fragment.assistedActivityViewModels( | |
noinline owner: () -> ComponentActivity = { requireActivity() }, | |
noinline defaultArgs: () -> Bundle? = { owner().intent?.extras }, | |
noinline instantiate: ViewModelInstantiate<VM>, | |
): Lazy<VM> = activityViewModels { | |
AssistedViewModelFactory(owner(), defaultArgs(), instantiate) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment