How do you save/store objects in SharedPreferences on Android?

后端 未结 20 2669
野趣味
野趣味 2020-11-22 13:35

I need to get user objects in many places, which contain many fields. After login, I want to save/store these user objects. How can we implement this kind of scenario?

<
20条回答
  •  暖寄归人
    2020-11-22 14:37

    Here's a take on using Kotlin Delegated Properties that I picked up from here, but expanded on and allows for a simple mechanism for getting/setting SharedPreference properties.

    For String, Int, Long, Float or Boolean, it uses the standard SharePreference getter(s) and setter(s). However, for all other data classes, it uses GSON to serialize to a String, for the setter. Then deserializes to the data object, for the getter.

    Similar to other solutions, this requires adding GSON as a dependency in your gradle file:

    implementation 'com.google.code.gson:gson:2.8.6'
    

    Here's an example of a simple data class that we would want to be able to save and store to SharedPreferences:

    data class User(val first: String, val last: String)
    

    Here is the one class that implements the property delegates:

    object UserPreferenceProperty : PreferenceProperty(
        key = "USER_OBJECT",
        defaultValue = User(first = "Jane", last = "Doe"),
        clazz = User::class.java)
    
    object NullableUserPreferenceProperty : NullablePreferenceProperty(
        key = "NULLABLE_USER_OBJECT",
        defaultValue = null,
        clazz = User::class.java)
    
    object FirstTimeUser : PreferenceProperty(
            key = "FIRST_TIME_USER",
            defaultValue = false,
            clazz = Boolean::class.java
    )
    
    sealed class PreferenceProperty(key: String,
                                             defaultValue: T,
                                             clazz: Class) : NullablePreferenceProperty(key, defaultValue, clazz)
    
    @Suppress("UNCHECKED_CAST")
    sealed class NullablePreferenceProperty(private val key: String,
                                                               private val defaultValue: T,
                                                               private val clazz: Class) : ReadWriteProperty {
    
        override fun getValue(thisRef: Any, property: KProperty<*>): T = HandstandApplication.appContext().getPreferences()
                .run {
                    when {
                        clazz.isAssignableFrom(String::class.java) -> getString(key, defaultValue as String?) as T
                        clazz.isAssignableFrom(Int::class.java) -> getInt(key, defaultValue as Int) as T
                        clazz.isAssignableFrom(Long::class.java) -> getLong(key, defaultValue as Long) as T
                        clazz.isAssignableFrom(Float::class.java) -> getFloat(key, defaultValue as Float) as T
                        clazz.isAssignableFrom(Boolean::class.java) -> getBoolean(key, defaultValue as Boolean) as T
                        else -> getObject(key, defaultValue, clazz)
                    }
                }
    
        override fun setValue(thisRef: Any, property: KProperty<*>, value: T) = HandstandApplication.appContext().getPreferences()
                .edit()
                .apply {
                    when {
                        clazz.isAssignableFrom(String::class.java) -> putString(key, value as String?) as T
                        clazz.isAssignableFrom(Int::class.java) -> putInt(key, value as Int) as T
                        clazz.isAssignableFrom(Long::class.java) -> putLong(key, value as Long) as T
                        clazz.isAssignableFrom(Float::class.java) -> putFloat(key, value as Float) as T
                        clazz.isAssignableFrom(Boolean::class.java) -> putBoolean(key, value as Boolean) as T
                        else -> putObject(key, value)
                    }
                }
                .apply()
    
        private fun Context.getPreferences(): SharedPreferences = getSharedPreferences(APP_PREF_NAME, Context.MODE_PRIVATE)
    
        private fun  SharedPreferences.getObject(key: String, defValue: T, clazz: Class): T =
                Gson().fromJson(getString(key, null), clazz) as T ?: defValue
    
        private fun  SharedPreferences.Editor.putObject(key: String, value: T) = putString(key, Gson().toJson(value))
    
        companion object {
            private const val APP_PREF_NAME = "APP_PREF"
        }
    }
    

    Note: you shouldn't need to update anything in the sealed class. The delegated properties are the Object/Singletons UserPreferenceProperty, NullableUserPreferenceProperty and FirstTimeUser.

    To setup a new data object for saving/getting from SharedPreferences, it's now as easy as adding four lines:

    object NewPreferenceProperty : PreferenceProperty(
            key = "NEW_PROPERTY",
            defaultValue = "",
            clazz = String::class.java)
    

    Finally, you can read/write values to SharedPreferences by just using the by keyword:

    private var user: User by UserPreferenceProperty
    private var nullableUser: User? by NullableUserPreferenceProperty
    private var isFirstTimeUser: Boolean by 
    
    Log.d("TAG", user) // outputs the `defaultValue` for User the first time
    user = User(first = "John", last = "Doe") // saves this User to the Shared Preferences
    Log.d("TAG", user) // outputs the newly retrieved User (John Doe) from Shared Preferences
    

提交回复
热议问题