Retention via ViewModel delegation
import android.arch.lifecycle.ViewModel | |
import android.arch.lifecycle.ViewModelProvider | |
import android.arch.lifecycle.ViewModelStoreOwner | |
import android.support.v4.app.Fragment | |
import android.support.v7.app.AppCompatActivity | |
import kotlin.reflect.KProperty | |
/** | |
* This class handles retention of any object using the ViewModel framework. An | |
* example of this method being used can be found in the Loader Manager framework | |
* in the Android support library. | |
*/ | |
class RetentionDelegate<T>( | |
private val viewModelStoreOwner: ViewModelStoreOwner, | |
private val initializer: (() -> T)? = null | |
) { | |
operator fun getValue(thisRef: Any?, property: KProperty<*>): T { | |
val (uniqueId, viewModel) = storeInformationFor(property) | |
// If the value is in the ViewModel, return it | |
@Suppress("UNCHECKED_CAST") | |
if (viewModel.values.containsKey(uniqueId)) return viewModel.values[uniqueId] as T | |
// If the viewModel doesn't hold the value and the initialiser is null, we're in an illegal state | |
initializer ?: throw IllegalStateException("Attempting to invoke getValue when no value is present") | |
val value = initializer.invoke() | |
// Add the value to the ViewModel | |
viewModel.values[uniqueId] = value as Any | |
return value | |
} | |
/** | |
* Convenience getter function for viewModel | |
*/ | |
private fun storeInformationFor(property: KProperty<*>): Pair<String, RetentionViewModel> { | |
// Get ViewModel | |
val viewModel = ViewModelProvider(viewModelStoreOwner)[RetentionViewModel::class.java] | |
// Use the property as a unique ID for the viewModel value map | |
val uniqueId = property.name | |
return uniqueId to viewModel | |
} | |
} | |
/** | |
* ViewModel class for holding the values to be retained in the viewModelStore | |
*/ | |
class RetentionViewModel: ViewModel() { | |
val values: MutableMap<String, Any> = hashMapOf() | |
} | |
/** | |
* Extension properties for ease of use | |
*/ | |
fun <T> Fragment.retained(valInitializer: (() -> T)? = null) = RetentionDelegate(this, valInitializer) | |
fun <T> AppCompatActivity.retained(valInitializer: (() -> T)? = null) = RetentionDelegate(this, valInitializer) |
class RetentionTestActivity: AppCompatActivity() { | |
val component by retained { instantiateDaggerComponent() } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment