Пользовательский вызов метода Kotlin get execute
для повышения читаемости вызовов SharedPreferences.Редактор я хочу использовать переменную Kotlin, которая будет выполнять " getSharedPreferences.edit () ' каждый раз, когда мне нужны новые SharedPreferences.Редактор. Изначально я собирался использовать что-то вроде этого:
val editPreferences: SharedPreferences.Editor = Application.getSharedPreferences("preferences", Context.MODE_PRIVATE).edit()
но затем мне сообщили, что "editPreferences" будет содержать ссылку на тот же редактор, когда я действительно хочу, чтобы он создавал новый редактор каждый раз, когда вызывается "editPreferences".
Если getter был использован будет ли каждый раз возвращаться новый редактор? Что-то вроде этого:--3-->
val editPreferences: SharedPreferences.Editor
get() = Application.getSharedPreferences("preferences", Context.MODE_PRIVATE).edit()
все еще встает и работает с Kotlin, и я не уверен, что метод get() будет содержать ссылку на редактор вместо создания нового.
4 ответов
второе объявление свойства соответствует вашим потребностям: оно имеет пользовательские геттер, таким образом, получение значения свойства всегда будет выполняться геттером, а значение не сохраняется (свойство не имеет поддержка поля).
вас, вероятно, смущает знак равенства get() = ...
, но это просто стенография с одним выражением для эквивалентной формы геттера:
val editPreferences: SharedPreferences.Editor
get() {
return Application
.getSharedPreferences("preferences", Context.MODE_PRIVATE)
.edit()
}
при реализации имущества с таможни добытчик, он не хранит никаких данных. Тело геттер будет выполняться каждый раз, когда вы получаете доступ к свойству.
вы можете сделать еще один шаг и обернуть свойство делегатом, используя имя переменной в метаданных.
использование
class SomeActivity : SomeBaseActivity {
// Declare property the with key "myImportantNumber"
// and default value 10
var myImportantNumber by preference(10)
//how to access the property
fun isMyImportantNumberReallyHight() = myImportantNumber > 100
//how to edit the property
fun incrementMyImportantNumber(times:Int){
myImportantNumber = myImportantNumber + times
}
}
делегация
делегат сохраняет экземпляр некоторого диспетчера предпочтений и использует метаданные свойства для извлечения и сохранения значений общих предпочтений.
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")
}
сахар
небольшой метод расширения:
fun <T> Activity.preference(default:T):DelegatedPreference<T>{
return DelegatedPreference(default, {this})
}
которые позволяют нам изменить это:
var myImportantNumber by DelegatedPreference(10, {this})
чем-то более читаемым:
var myImportantNumber by preference(10)
фактическое получение и сохранение
вот что я назвал PreferencesManager
(извините, я не придумал лучшего имени) делает тяжелый подъем и называет .edit()
каждый раз, когда свойство должно быть изменено. Это будет выглядеть примерно так:
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
}
здесь есть много возможностей для улучшения (например, параметризация имени предпочтения вместо его жесткого кодирования, предоставление точки расширения для сериализация других типов, и т. д.), Но общая идея остается.
As клавиша и yole упомянуто, пользовательский геттер приведет к возвращению нового редактора каждый раз, что вы хотите.
однако, пожалуйста, рассмотрите это экстра-причудливое решение, которое использует:
- подстановкой чтобы уменьшить накладные расходы на вызов функции
-
расширения чтобы это выглядело как метод
Context
класс, хотя мы не определили это -
функции более высокого порядка чтобы мы могли избавиться от вызова
commit()
после этого при его использовании
декларация
inline fun Context.editPreferences(preferenceFileName:String = "preferences",block:SharedPreferences.Editor.() -> Unit)
{
val editablePreferences = getSharedPreferences(preferenceFileName,Context.MODE_PRIVATE).edit()
editablePreferences.block()
editablePreferences.commit()
}
использование
Application.editPreferences()
{
putBoolean("SOME_BOOLEAN",true)
putFloat("SOME_FLOAT",293232F)
}
или во многих случаях, когда приемник уже Context
можно сделать так:
editPreferences()
{
putBoolean("SOME_BOOLEAN",true)
putFloat("SOME_FLOAT",293232F)
}
❤Котлин