一、前言
- 在項目中很多很多的頁面用了很多的枚舉,而產品和需求發對完發完版本這個枚舉更改過很多次。或者前端與後端更改沒有通知我們移動端,導致出現移動端前端不一樣的展示的問題,所以決定枚舉有後端返回 key,value的形式我們自己去匹配查找value展示。這樣避免了我們因爲這個問題而發版。
- 雖然說目前服務返回了只有幾種類型的枚舉(例如:公司類型大約有15個左右,單據類型有10多個,發票類型有10個左右......)但是以後肯定還會繼續添加,還有可能會把目前項目使用的枚舉進行遷移。所以考慮到存儲到本地避免多次請求。
二、 爲啥要使用Room
目前項目中使用的時MVP模式開發,如果以後改爲MVVM對於數據請求頁面緩存優化更友好(Room返回livedata使用viewmodel觀察數據變化進行更新)。
在網上搜索了一下Greedao與Room對比插入和查詢,Room更佔優勢
三、基本使用
- 導入依賴
roomRuntime = "androidx.room:room-runtime:$room_version",
roomCompiler = "androidx.room:room-compiler:$room_version",
// RxJava support for Room
roomRxjava2 = "android.arch.persistence.room:rxjava2:$room_version",
roomKapt = "androidx.room:room-compiler:2.2.5"
- 插件
apply plugin: 'kotlin-kapt'
- 創建表
@Entity
data class EnumData(
@PrimaryKey
var id: Long = 0,
var costApplicationTypes: HashMap<String, String>? = null,
var noCostApplicationTypes: HashMap<String, String>? = null,
var zongbuInvoiceTitles: HashMap<String, String>? = null,
var firmTypes: HashMap<String, String>? = null
)
-
註解
@Entity
需要在創建的表@PrimaryKey
鍵 (@PrimaryKey(autoGenerate = true)
設置鍵自增)@TypeConverters(TypeConverter::class)
(TypeConverter
需要自己創建並寫兩個方法使用@TypeConverter
標註例:
class MapTypeConverter {
@TypeConverter
fun stringToMap(value: String): HashMap<String, String> {
return Gson().fromJson(value, object : TypeToken<HashMap<String, String>>() {}.type)
}
@TypeConverter
fun mapToString(value: HashMap<String, String>?): String {
return if (value == null) "" else Gson().toJson(value)
}
}
上面是map的轉換,也就是說如果你想要往數據庫中寫入Map數據需要MapTypeConverter
和在其上使用@TypeConverters
- 創建 AppDatabase
@Database(entities = [EnumData::class], version = 4, exportSchema = false)
@TypeConverters(MapTypeConverter::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun enumDataDao(): EnumDataDao
companion object {
@Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase =
INSTANCE ?: synchronized(this) {
INSTANCE ?: buildDatabase(context).also {
INSTANCE = it
}
}
private fun buildDatabase(context: Context) =
Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java, "admin.db"
)
//數據結構發生改變不加fallbackToDestructiveMigration()會引起APP崩潰。作用:更新版本之後清空數據庫
.fallbackToDestructiveMigration()
//可在主線程操作
.allowMainThreadQueries()
.build()
}
}
@TypeConverters(MapTypeConverter::class)
如還有List的數據需要添加list的Converter
- 創建EnumDataDao
/**
*
* @Description Room 數據庫 增刪改查方法
* @date 2020/9/15 4:13 PM
* @author BryceCui
* @Version 1.0
*
* 1、Completable:只有onComplete和onError方法,即只有“完成”和“錯誤”兩種狀態,不會返回具體的結果。
* 2、Single:其回調爲onSuccess和onError,查詢成功會在onSuccess中返回結果,需要注意的是,如果未查詢到結果,即查詢結果爲空,會直接走onError回調,拋出EmptyResultSetException異常。
* 3、Maybe:其回調爲onSuccess,onError,onComplete,查詢成功,如果有數據,會先回調onSuccess再回調onComplete,如果沒有數據,則會直接回調onComplete。
* 4、Flowable/Observable:這是返回一個可觀察的對象,查詢的部分有變化時,都會回調它的onNext方法,沒有數據變化的話,不回調。直到Rx流斷開。
*/
@Dao
interface EnumDataDao {
@Transaction
@Query("SELECT * FROM enumdata ORDER BY id DESC LIMIT 1")
fun getAllEnumData():Maybe<EnumData?>
/**
* OnConflictStrategy.REPLACE:衝突策略是取代舊數據同時繼續事務
* OnConflictStrategy.ROLLBACK:衝突策略是回滾事務
* OnConflictStrategy.ABORT:衝突策略是終止事務
* OnConflictStrategy.FAIL:衝突策略是事務失敗
* OnConflictStrategy.IGNORE:衝突策略是忽略衝突
*/
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertEnumData(data: EnumData)
}
- 插入使用
/**
* 插入枚舉到數據庫
*/
fun insertEnumOnRoom(response: EnumData): Disposable? {
return Single.fromCallable {
AppDatabase.getInstance(AdminApplication.instance!!).enumDataDao().insertEnumData(response)
}.subscribeOn(Schedulers.io()).observeOn(Schedulers.io()).doOnError {
Log.e("doOnError", "doOnError")
}.doOnSuccess {
Log.e("doOnSuccess", "doOnSuccess")
}.subscribe()
}
- 查詢使用
/**
* 從數據庫獲取所有枚舉
*/
fun getAllEnumOnRoom() {
AppDatabase.getInstance(AdminApplication.instance!!).enumDataDao().getAllEnumData().subscribeOn(Schedulers.io()).observeOn(Schedulers.io())
.doOnSuccess {
AdminApplication.instance!!.enumData = it
Log.e("doOnNext", it.toString())
}
.doOnError {
Log.e("getAllEnum", it.toString())
}.doOnComplete {
Log.e("getAllEnum", "doOnComplete")
}.subscribe()
}
四、數據庫升級需要注意
- 升級需要自己寫升級的SQL語句(都有哪些改動)
- 自行百度
五、總結
增刪改查需要自己寫SQL語句有點......
對非基礎類型存儲不是很友好需要自己寫
TypeConverters
而寫好像一個List<T>
一種T
需要一個。這個目前沒有找到寫一種的方法。最後 寫的不好 不喜勿噴哈!!! 但接受糾正。