Skip to content

Instantly share code, notes, and snippets.

@jamiesanson
Last active August 12, 2019 22:12
Show Gist options
  • Save jamiesanson/350910d5f4eba3e909ed99cc96741556 to your computer and use it in GitHub Desktop.
Save jamiesanson/350910d5f4eba3e909ed99cc96741556 to your computer and use it in GitHub Desktop.
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