android-ktx icon indicating copy to clipboard operation
android-ktx copied to clipboard

SharedPreferences delegates

Open jmfayard opened this issue 7 years ago • 2 comments

Request: abstract with a properties delegate how to get and update the data stored in the SharedPreferences

It's not merely about "reducing boilerplate" but also more importantly about decoupling the app logic from the android framework.

Example

interface CurrentUser {
    var userId: Int
    var fullName: String
    var backendToken: String
}

class SharedPrefsCurrentUser(
   val preferences: SharedPreferences
) : CurrentUser {
    override var userId by preferences.bindPreference(default = -1)
    override var fullName by preferences.bindPreference(default = "")
    override var backendToken by preferences.bindPreference(default = "")
}

data class TestCurrentUser(
    override var userId: String = -1,
    override var fullName: String = "",
    override var backendToken: String = ""
) : CurrentUser

There are of course already libraries providing that (I'm using curently kotlin-jetpack )

But it's such a useful pattern for a core function that the more the better. The alternative is people doing stupid mocking dance, having a mocked context that returned a mocked shared preferences, configured to return "blah" when getString("foo") is called. Compare that with using a data class!

jmfayard avatar Feb 08 '18 12:02 jmfayard

I like this approach: https://hackernoon.com/kotlin-delegates-in-android-development-part-1-50346cf4aed7

which results in:

class MyClass(prefs: SharedPreferences) {
    var count by prefs.int()
}

still having teh possibility to specify the key and default manually

tobiasschuerg avatar Mar 22 '18 16:03 tobiasschuerg

Yes, unfortunately it does not handle nullability issues.

I think the best option is following.

class SharedPrefsCurrentUser(
   val preferences: SharedPreferences
) : CurrentUser {
    override var userId : Int by preferences.int().defaultBy(0)
    override var fullName : String by preferences.string().defaultBy(0)
    override var backendToken : String? by preferences.string()
}

I think default binder should create delegate for nullable. Only when you provide default, should it create not-null.

Ioane5 avatar Aug 31 '18 10:08 Ioane5