Room 替換 SP 的可行性實踐

對比

SharedPreference

簡稱SP,使用鍵值對的形式保存原始類型的數據,默認以XML格式的文件來存儲這些數據java

  • 適用場景:存儲量小、簡單的數據
  • 優缺點:有本身的內存級的緩存,在數據量小的時候讀取較快,可是跨進程不安全,數據量大的時候加載緩慢,全量寫入,容易引發ANR

sqlite, Room

Room並非一個數據庫,他是在 sqlite 的基礎上提供了一個抽象層,讓用戶可以在充分利用 SQLite 的強大功能的同時,獲享更強健的數據庫訪問機制。並保留了靈活的接口適配層。sql

@Database(entities = [KeyValue::class], version = 1, exportSchema = true)
abstract class KvStore : RoomDatabase(), CoroutineScope by MainScope() {
    companion object {
        val database by lazy {
            Room.databaseBuilder(
                SwUtils.application, KvStore::class.java, "key_value_database.db"
            )
                .allowMainThreadQueries()
                .build()
        }
        
        fun <T : Any> get(key: String, defaultValue: T): T {
            val type = defaultValue::class.simpleName ?: ""
            val value = database.dao().get(key, type)
            return try {
                val v = when (defaultValue) {
                    is String -> value
                    is Boolean -> value == "true"
                    is Int -> value.toInt()
                    is Float -> value.toFloat()
                    is Double -> value.toDouble()
                    else -> Gson().fromJson(value, defaultValue::class.java)
                }
                v as T
            } catch (e: Throwable) {
                defaultValue
            }
        }
        
        fun <T : Any> set(key: String, value: T) {
            val type = value::class.simpleName ?: ""
            val v = when (value) {
                is String, is Boolean, is Int, is Float, is Double -> value.toString()
                else -> Gson().toJson(value)
            }
            database.dao().insertReplace(KeyValue(key, type, v))
        }

        inline fun <reified T> liveData(key: String, sticky: Boolean = true): MediatorLiveData<T> {
            var realSticky = sticky
            val type = T::class.simpleName ?: ""
            val mld = MediatorLiveData<T>()
            mld.addSource(database.dao().liveData(key, type)) {
                if (realSticky) {
                    mld.value = try {
                        Gson().fromJson(it, T::class.java)
                    } catch (e: Throwable) {
                        null
                    }
                } else {
                    realSticky = true
                }
            }
            return mld
        }
    }

    abstract fun dao(): KeyValueDao
}

@Entity(primaryKeys = ["key", "type"])
data class KeyValue(
    @ColumnInfo(name = "key", defaultValue = "")
    var key: String = "",
    @ColumnInfo(name = "type", defaultValue = "")
    var type: String = "",
    @ColumnInfo(name = "value", defaultValue = "")
    var value: String = ""
)

@Dao
abstract class KeyValueDao : BaseDao<KeyValue>() {
    @Query("SELECT value from KeyValue WHERE `key` = :key AND type = :type")
    abstract fun get(key: String, type: String): String

    @Query("SELECT value from KeyValue WHERE `key` = :key AND type = :type")
    abstract fun liveData(key: String, type: String): LiveData<String>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    abstract fun insertReplace(obj: KeyValue): Long
}
複製代碼

最後

可複製代碼或者根據該思路擴展
優勢:數據庫

  1. 不須要引入額外的三方庫
  2. 在kv存儲的基礎上,利用room的特性增長了數據監聽
相關文章
相關標籤/搜索