Kotlin自定义是否获得执行方法调用

为了增加对SharedPreferences.Editor的调用的可读性,我希望每次需要一个新的SharedPreferences.Editor时,使用一个Kotlin变量来执行“getSharedPreferences.edit()”。 最初我打算使用这样的东西:

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

但后来我被告知,'editPreferences'将保持对同一个编辑器的引用,当我每次调用'editPreferences'时我真正想要它创建一个新的编辑器。

如果使用自定义getter,每次都会返回一个新的编辑器? 像这样的东西:

 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实现属性,则不会存储任何数据。 每次访问该属性时,都会执行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 } 

在这里有很大的改进空间(比如参数化首选项名称,而不是硬编码,给出序列化其他类型的扩展点等等),但总体思路依然存在。

正如热键和提到的那样,自定义的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) } 

Kotlin❤