一次Room在项目中的实践

一、前言

  • 在项目中很多很多的页面用了很多的枚举,而产品和需求发对完发完版本这个枚举更改过很多次。或者前端与后端更改没有通知我们移动端,导致出现移动端前端不一样的展示的问题,所以决定枚举有后端返回 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? = null,

        var noCostApplicationTypes: HashMap? = null,

        var zongbuInvoiceTitles: HashMap? = null,

        var firmTypes: HashMap? = null
)
  • 注解

    @Entity 需要在创建的表

    @PrimaryKey键 (@PrimaryKey(autoGenerate = true)设置键自增)

    @TypeConverters(TypeConverter::class)TypeConverter需要自己创建并写两个方法使用@TypeConverter标注例:

class MapTypeConverter {

    @TypeConverter
    fun stringToMap(value: String): HashMap {
        return Gson().fromJson(value, object : TypeToken>() {}.type)
    }
    @TypeConverter
    fun mapToString(value: HashMap?): 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

    /**
     * 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 需要一个。这个目前没有找到写一种的方法。

  • 最后 写的不好 不喜勿喷哈!!! 但接受纠正。

你可能感兴趣的:(一次Room在项目中的实践)