存储在“房间”表中的设置只有一个条目,可触发任何参数更新的所有观察者

时间:2019-04-08 09:15:13

标签: android android-room android-livedata

我正在使用简单的“房间”表进行设置

@Entity
data class Settings(var user: String = "") {
    @PrimaryKey
    var id: Long = 1

    var activeItem: Int = 0
    var developerMode: Boolean = false
    var logoUrl: String = ""
    var advertisment: String = ""
}

我观察到LiveData表的变化。问题是,如果所有数据都在id = 1的一个条目中,那么当表中的任何值更新时,总是会触发所有观察者。有什么方法可以强制LiveData仅在参数更改时(而不是整个条目)进行观察? 我不想通过其他表来解决它,也不想将其存储在具有不同ID的条目中

以下是来自Dao的查询:

@Query("SELECT activeItem FROM Settings WHERE id = 1")
abstract fun getActiveItem(): LiveData<Int>

@Query("SELECT user FROM Settings WHERE id = 1")
abstract fun getUser(): LiveData<String>

@Query("SELECT developerMode FROM Settings WHERE id = 1")
abstract fun getDeveloperMode(): LiveData<Boolean>

@Query("SELECT logoUrl FROM Settings WHERE id = 1")
abstract fun getLogoUrl(): LiveData<String>

@Query("SELECT advertisment FROM Settings WHERE id = 1")
abstract fun getAdvertisment(): LiveData<String>

1 个答案:

答案 0 :(得分:0)

您应使用SharedPreferences保留用户首选项。您可以通过首选项更改监听器收听首选项更新

preferences.registerOnSharedPreferenceChangeListener { sharedPreferences, key -> 
    // handle preference update
}

或者您可以实现自己的首选项注册表。


  1. 将您的偏好设置模型定义为sealed class

    sealed class MyPreference
    
    data class ActiveItemPreference(val number: Int) : MyPreference()
    data class UserPreference(val name: String, val age: Int) : MyPreference()
    
  2. PreferenceRegistry作为类型安全的异构容器(有效Java(第3版)。第33条)

    object PreferencesRegistry {
    
        private val preferenceLiveDataMap: Map<KClass<*>, MutableLiveData<MyPreference>> =
                HashMap<KClass<*>, MutableLiveData<MyPreference>>().apply {
                    addPreferenceLiveData(ActiveItemPreference::class)
                    addPreferenceLiveData(UserPreference::class)
                    /*
                     Or you if you use kotlin-reflect you can register your preferences like this
                    Preference::class.sealedSubclasses.forEach { preferenceClass ->
                        addPreferenceLiveData(preferenceClass)
                    }
                    */
                }
    
        operator fun <T : MyPreference> get(preferenceType: KClass<T>): LiveData<T> {
            @Suppress("UNCHECKED_CAST") val liveData = preferenceLiveDataMap[preferenceType] as? LiveData<T>
            return liveData ?: throw AssertionError("Unexpected preference type $preferenceType")
        }
    
        /**
         * Store receiver [T] of [toPreferences] extension to receiver [SharedPreferences] of [action]
         */
        fun <T : MyPreference> T.toPreferences(context: Context, action: SharedPreferences.(T) -> Unit) {
            // get shared preferences to store T
            context.getSharedPreferences("preferences", Context.MODE_PRIVATE).action(this)
            // send new value of preference T to observers
            preferenceLiveDataMap[this::class]?.postValue(this) ?: AssertionError(
                    "Unable to update preference live data of type ${this::class}")
        }
    
        /**
         * Helper extension for type safety
         */
        private fun <T : MyPreference> MutableMap<KClass<*>, MutableLiveData<MyPreference>>.addPreferenceLiveData(type: KClass<T>) {
            put(type, MutableLiveData())
        }
    }
    

    看看以DSL方式实现的toPreferences扩展,您可以在《行动中的科特琳》(项目11.2.1)Type-Safe Builders文章中阅读有关此方法的更多信息。

  3. 现在您可以保存属性

    UserPreference("Tom", 12).toPreferences(context) { (name, age) ->
        // extension for SharedPreferences from Android SDK
        edit {
            putString("USER_NAME", name)
            putInt("USER_AGE", age)
        }
    }
    
  4. 观察变化

    PreferencesRegistry[UserPreference::class].observe(this::getLifecycle) { userPref ->
        if (userPref == null)
            Log.w("PREFERENCES", "Unexpected nullable user preference")
        else
            Log.d("PREFERENCES", "User preference updated. New name is ${userPref.name} and new age is ${userPref.age}")
    }
    
  5. 加载实施偏好设置并在应用程序启动时调用