Skip to content

Instantly share code, notes, and snippets.

@fergusonm
Created December 30, 2021 16:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fergusonm/743ec5cdc8bc2881d6b0706aa4d57f2a to your computer and use it in GitHub Desktop.
Save fergusonm/743ec5cdc8bc2881d6b0706aa4d57f2a to your computer and use it in GitHub Desktop.
Multiplatform view model with a backing android VM
class MyMultiPlatformViewModel @Inject constructor(
private val scope: CoroutineScope,
private val stateHelper: SavedStateHelper,
) : CoroutineScope by scope, AutoCloseable {
private var screenId: String by stateHelper.savedState("screenId", default = "")
fun doAThing() {}
override fun close() {
// clean up resources
}
}
private class PersistentStateDelegate<T: Any>(
private val holder: SavedStateHandle,
private val key: String,
private val default: T
) : ReadWriteProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>): T {
return holder.get<T>(getKey(thisRef))
?: default.also { setValue(thisRef, property, it) }
}
override fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
holder.set(getKey(thisRef), value)
}
private fun getKey(thisRef: Any) = "${thisRef.javaClass.name}__$key"
}
class BackingAndroidVM(
private val stateHandle: SavedStateHandle
) : ViewModel(), SavedStateHelper {
private val persisted = mutableMapOf<Class<*>, Any>()
fun <T: Any> getOrCreate(clazz: Class<T>, create: (CoroutineScope, SavedStateHelper) -> T) =
persisted.getOrPut(clazz) { create.invoke(viewModelScope, this) } as T
override fun <T: Any, VM : Any> savedState(key: String, default: T): ReadWriteProperty<VM, T> {
return PersistentStateDelegate(stateHandle, key, default)
}
override fun onCleared() {
super.onCleared()
persisted.keys.filterIsInstance<AutoCloseable>().forEach { it.close() }
}
}
inline fun <reified T : Any> Fragment.getOrCreatePersisted(noinline create: (CoroutineScope, SavedStateHelper) -> T): T {
val persistentStorageVM = ViewModelProvider(this, SavedStateViewModelFactory(requireActivity().application, this)).get<BackingAndroidVM>()
return persistentStorageVM.getOrCreate(T::class.java, create)
}
inline fun <reified T : Any> ComponentActivity.getOrCreatePersisted(noinline create: (CoroutineScope, SavedStateHelper) -> T): T {
val persistentStorageVM = ViewModelProvider(this, SavedStateViewModelFactory(application, this)).get<BackingAndroidVM>()
return persistentStorageVM.getOrCreate(T::class.java, create)
}
interface SavedStateHelper {
fun <T: Any, VM : Any> savedState(key: String, default: T): ReadWriteProperty<VM, T>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment