Home > Mobile >  Get android preferences with kotlin generics
Get android preferences with kotlin generics

Time:10-12

I want to get string from SharedPreferences and then with generics convert it to so some class. I have this code:

fun <T> get(key: String): T? {
    val value = sharedPreferences.getString(key, "") ?: ""
    (value as? T)?.let { return it }

    return if (value.isNotEmpty()) {
        try {
            Gson().fromJson(value, object : TypeToken<T>() {}.type)
        } catch (exc: Exception) {
            null
        }
    } else {
        null
    }
}

And I call this function like this:

preferences.get<UserInfoBuilder>(PreferencesCoreKeys.USER_INFO)

But inside get fun I see that (value as? T) is just a String. And calling object : TypeToken<T>() {}.type gives me an error "not enough information about type". How to make it work?

CodePudding user response:

Casting does not convert types to other types. It is only a promise you make to the compiler that the instance you are working with already is that other type.

If you call sharedPreferences.getString, you will always get a String returned. you can't successfully cast Strings to anything besides the types it already is (Any, CharSequence, Comparable<String>, or the nullable versions of those). So even with reified types, the as? T cast will always fail unless T is one of those. Without reified types, it will succeed at the call site, and then crash later when you try to use the instance as something other than a String.

And Gson must know the concrete type you are requesting, so you need to use reified generics.

inline fun <reified T> get(key: String): T? {
    val value = sharedPreferences.getString(key, "") ?: ""
    return if (T::class == String::class) {
        value as T 
    } else {
        try { Gson().fromJson(value, T::class.java) }
        catch(e: Exception) { null }
    }
}
  • Related