Пользовательский вызов метода 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 упомянуто, пользовательский геттер приведет к возвращению нового редактора каждый раз, что вы хотите.

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

декларация

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)
}

❤Котлин