0

I am working on an Android app in which I have to make changes to my HomeScreen by observing LiveData of SharedPreferences which lives in Settings screen. I am following MVVM architecture for it.

I have already checked this LiveData with shared preferences, but it has a lot of boilerplate in the form of creating different classes for different types of SharedPreferences data. I am looking for something more generic. That is why I have created a LiveSharedPreference class and getter for SharedPreferences with Kotlin extension functions and reified types. Here is the custom LiveData class and SharedPreferences getter.

/**************** LiveSharedPreferences.kt ****************/
class LiveSharedPreferences<T : Any>(
    private val sharedPreferences: SharedPreferences, private val preferenceKey: String,
    private val defValue: T, private val clas: Class<T>
) : LiveData<T>() {

    private val preferenceChangeListener =
        SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
            if (key == preferenceKey) {
                // error in this line 
                value = sharedPreferences.get(key, defValue)
            }
        }


    override fun onActive() {
        super.onActive()

        // error in this line 
        value = sharedPreferences.get(preferenceKey, defValue)
        sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener)
    }

    override fun onInactive() {
        sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener)
        super.onInactive()
    }
}

/****** Custom getter with reified type T defined in Extensions.kt ******/
inline fun <reified T: Any> SharedPreferences.get(prefKey: String?, defaultValue: T? = null): T? {
    return when (T::class) {
        String::class -> getString(prefKey, defaultValue as? String) as T?
        Int::class -> getInt(prefKey, defaultValue as? Int ?: -1) as T?
        Boolean::class -> getBoolean(prefKey, defaultValue as? Boolean ?: false) as T?
        Float::class -> getFloat(prefKey, defaultValue as? Float ?: -1f) as T?
        Long::class -> getLong(prefKey, defaultValue as? Long ?: -1) as T?
        else -> throw UnsupportedOperationException("Invalid operation")
    }
}

But using this get function gives me an error: Cannot use 'T' as reified type parameter. Use a class instead I know it has something to do with the way I am dealing with type T. Is there a way I can deal with this problem without much boilerplate?

Abdul Mateen
  • 1,418
  • 1
  • 14
  • 32
  • dont use this reified function, it creates a ton of overhead. Creating separate function for each class is the correct approach. – Pawel Sep 02 '19 at 10:26
  • Is this overhead more than the effect of creating extra classes? – Abdul Mateen Sep 03 '19 at 06:41
  • 1
    Yes, `inline` keyword causes your entire functions body to get effectively copied into calling place. I answered similar question in detail [here](https://stackoverflow.com/questions/52526287/reified-inline-function-for-arrays/52527282#52527282). – Pawel Sep 03 '19 at 10:24

0 Answers0