Производит ли вызов Kotlin метод вызова метода

Чтобы повысить удобочитаемость вызовов в SharedPreferences.Editor, я хочу использовать переменную Kotlin, которая будет выполнять «getSharedPreferences.edit ()» каждый раз, когда мне нужен новый SharedPreferences.Editor. Первоначально я собирался использовать что-то вроде этого:

val editPreferences: SharedPreferences.Editor = Application.getSharedPreferences("preferences", Context.MODE_PRIVATE).edit() 

Но потом мне сообщили, что «editPreferences» будет содержать ссылку на тот же редактор, когда я действительно хочу, чтобы он создавал новый редактор каждый раз, когда вызывается «editPreferences».

Если бы использовался пользовательский приемник, каждый раз возвращался новый редактор? Что-то вроде этого:

 val editPreferences: SharedPreferences.Editor get() = Application.getSharedPreferences("preferences", Context.MODE_PRIVATE).edit() 

Все еще вставая и работая с Kotlin, и я не уверен, что метод get () будет ссылаться на редактор вместо создания нового.

Вторая декларация свойства соответствует вашим потребностям: у нее есть пользовательский getter , поэтому получение значения свойства всегда будет выполнять getter, и значение не сохраняется (свойство не имеет поля поддержки ).

Вероятно, вас смущает знак равенства в get() = ... , но это всего лишь сокращение одного выражения для эквивалентной формы getter:

 val editPreferences: SharedPreferences.Editor get() { return Application .getSharedPreferences("preferences", Context.MODE_PRIVATE) .edit() } 

Если вы реализуете свойство с пользовательским getter, оно не будет хранить какие-либо данные. Тело получателя будет выполняться каждый раз при доступе к собственности.

Вы можете сделать еще один шаг и обернуть свойство делегатом, используя имя переменной в метаданных.

Применение

 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 } 

Здесь есть много возможностей для улучшения (например, параметрирование имени предпочтительности вместо жесткого кодирования, предоставление точки расширения для сериализации других типов и т. Д.), Но общая идея остается.

Как упоминалось как горячая клавиша и yole , пользовательский getter будет каждый раз возвращать новый редактор, что вам и нужно.

Однако, пожалуйста, рассмотрите это экстраординарное решение, которое использует:

  • вложение для уменьшения накладных расходов при вызове функции
  • чтобы сделать его похожим на метод класса 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) } 

Котлин ❤