Skip to content

Instantly share code, notes, and snippets.

@thegarlynch
Created March 19, 2020 13:19
Show Gist options
  • Save thegarlynch/a302d56e961ac73878579a233a7b1787 to your computer and use it in GitHub Desktop.
Save thegarlynch/a302d56e961ac73878579a233a7b1787 to your computer and use it in GitHub Desktop.
configurasi-viewmodel-savedstatehandle
@file:Suppress("UNCHECKED_CAST")
package com.thegar.example.helper.viewmodel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import kotlin.properties.ReadOnlyProperty
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
class SavedInstanceStateLiveDataDelegate<T>(
private val handle: SavedStateHandle,
private val initial: T,
private val key : String?,
private val distinctOnly : Boolean
) : ReadOnlyProperty<Any?, MutableLiveData<T>> {
override fun getValue(thisRef: Any?, property: KProperty<*>): MutableLiveData<T> {
val instanceKey = key ?: property.name
var liveData = handle.getLiveData<Any?>(instanceKey, initial)
if(distinctOnly){
liveData = LiveDataDistinctWrapper(liveData)
}
val returnedValue : MutableLiveData<T>
if(initial is Set<*>){
returnedValue = (liveData as MutableLiveData<Array<*>>).map { it.toSet() } as MutableLiveData<T>
}else{
returnedValue = liveData as MutableLiveData<T>
}
return returnedValue
}
}
class LiveDataDistinctWrapper<T>(private val liveData: MutableLiveData<T>) : MediatorLiveData<T>(){
init {
addSource(liveData.distinctUntilChanged()){
super.setValue(it)
}
}
override fun getValue(): T? {
return liveData.value
}
override fun postValue(value: T) {
liveData.postValue(value)
}
override fun setValue(value: T) {
liveData.value = value
}
}
class SavedInstanceStateDelegate<T>(
private val handle: SavedStateHandle,
private val initial: T,
private val key : String?
) : ReadWriteProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
val instanceKey = key ?: property.name
if(!handle.contains(instanceKey)) {
if (initial is Set<*>) {
handle.set(instanceKey, initial.toTypedArray())
} else {
handle.set(instanceKey, initial)
}
}
val value = handle.get<Any?>(instanceKey)
val returnedValue : T
if(value != null && initial is Set<*>){
returnedValue = (value as Array<*>).toSet() as T
}else{
returnedValue = value as T
}
return returnedValue ?: initial
}
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val instanceKey = key ?: property.name
if(initial != null && initial is Set<*>){
handle.set(instanceKey, (value as Set<*>).toTypedArray())
}else{
handle.set(instanceKey, value)
}
}
}
/**
*
* @return savedInstanceState as live data
*
*/
fun <T> SavedStateHandle.liveData(initial: T, key : String? = null, distinctOnly: Boolean = true) : SavedInstanceStateLiveDataDelegate<T>{
return SavedInstanceStateLiveDataDelegate(this, initial, key, distinctOnly)
}
/**
* if you changed the property that is delegated by this, it would update
* savedInstanceState automatically
*
* @return savedInstanceState as it's value
*/
fun <T> SavedStateHandle.delegate(initial: T, key : String? = null) : SavedInstanceStateDelegate<T>{
return SavedInstanceStateDelegate(this, initial, key)
}
fun <T> SavedStateHandle.liveData(initial : LiveData<T>, key : String? = null, distinctOnly: Boolean = true) : SavedInstanceStateLiveDataDelegate<T?>{
return SavedInstanceStateLiveDataDelegate(this, initial.value, key, distinctOnly)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment