You can take another step and wrap the property with a delegate using the variable name in the metadata.
Using
class SomeActivity : SomeBaseActivity {
Delegation
A delegate stores an instance of some preference manager and uses metadata in the property to retrieve and store values ββin general preferences.
class DelegatedPreference<T>(val default: T, val contextProvider:()-> Context) { val manager by lazy { PreferencesManager(contextProvider()) } @Suppress("UNCHECKED_CAST") operator fun getValue(thisRef: Any?, prop: KProperty<*>): T { return manager.get(prop.name, default) } operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: Any) { manager.save(prop.name, value) } class TypeNotImplementedException(val propName:String) : Exception("Type of ${propName} is not implemented on DelegatedPreference and thus invalid") }
Some sugar
A small extension method:
fun <T> Activity.preference(default:T):DelegatedPreference<T>{ return DelegatedPreference(default, {this}) }
This allows us to change this:
var myImportantNumber by DelegatedPreference(10, {this})
Something more readable:
var myImportantNumber by preference(10)
Actual retrieval and retention
Here, what I called the PreferencesManager (sorry, I did not come up with a better name) does the hard work and calls .edit() every time the property needs to be changed. It would look like this:
public class PreferencesManager(context: Context) { private val preferences = getSharedPreferences(context) companion object Utils { public val APP_PREFERENCES: String = "APP_PREFERENCES" fun getSharedPreferences(context: Context): SharedPreferences { return context.getSharedPreferences(APP_PREFERENCES, Context.MODE_PRIVATE) } } public fun save(label:String, elem:Any){ when(elem){ is Int -> preferences.edit().putInt(label, elem).apply() is String -> preferences.edit().putString(label, elem).apply() is Float -> preferences.edit().putFloat(label, elem).apply() is Boolean -> preferences.edit().putBoolean(label, elem).apply() else -> throw DelegatedPreference.TypeNotImplementedException(label) } } @Suppress("UNCHECKED_CAST", "IMPLICIT_CAST_TO_ANY") public fun <T> get(label:String, default:T):T = when(default){ is Int -> preferences.getInt(label, default) is String -> preferences.getString(label, default) is Float -> preferences.getFloat(label, default) is Boolean -> preferences.getBoolean(label, default) else -> throw DelegatedPreference.TypeNotImplementedException(label) } as T }
There are many opportunities for improvement (for example, parameterizing the preference name instead of hard coding, providing an extension point for serializing other types, etc.), but the general idea remains.