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

时间:2016-04-01 22:25:13

标签: android kotlin

为了提高对SharedPreferences.Editor的调用的可读性,我想使用每次需要新的SharedPreferences.Editor时执行'getSharedPreferences.edit()'的Kotlin变量。最初我打算用这样的东西:

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()方法是否会保留对编辑器的引用而不是创建新的编辑器。

4 个答案:

答案 0 :(得分:6)

如果使用自定义getter实现属性,则不会存储任何数据。每次进入酒店时都会执行吸气剂的主体。

答案 1 :(得分:5)

你可以更进一步,用一个委托包装属性,利用元数据上的变量名。

用法

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

}

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

答案 2 :(得分:3)

第二个属性声明符合您的需求:它具有custom getter,因此获取属性值将始终执行getter,并且不存储该值(该属性没有backing field)。< / p>

您可能会被get() = ...中的等号感到困惑,但对于等效形式的getter,它只是single-expression shorthand

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

答案 3 :(得分:3)

提到hotkeyyole时,自定义getter会导致每次都返回一个新的编辑器,这就是你想要的。

但是,请考虑使用以下特殊解决方案:

声明

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❤