阅读 827

android Jetpack ROOM数据库结合其它Library的使用介绍

ROOM数据库结合其它Library的使用介绍

本文主要介绍room数据库配合其它Library的使用介绍,基本用法请查看Android Jetpack ROOM数据库用法介绍

room数据库默认不允许在ui线程操作数据库

比如查询数据只能先创建一个子线程操作

@Dao
abstract class UserDao {

    @Query("select * from tab_user")
    abstract fun getAll(): List<User>
}


class RoomActivity : AppCompatActivity() {
    private var adapter: RoomAdapter? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_room)
        title = "Room Example"
        AppDataBase.getInstance().mockData()
        initRecyclerView()
    }

    fun queryUser(view: View) {
        loadUser()
    }
    
    private fun loadUser() {
    	//必须在子线程操作
        Thread {
            val data = AppDataBase.getInstance().userDao().getAll()
            runOnUiThread {
                adapter?.data = data
            }
        }.start()
    }
    
    ...
}
复制代码

当然可以调用allowMainThreadQueries()方法改变room数据库的默认配置,允许在ui线程查询数据,但个人强烈不建议这么做

可以使用以下几种方式操作数据库

结合LiveData

首先添加LiveData需要的相关依赖(一般下面的依赖会自动导入)

implementation "androidx.lifecycle:lifecycle-runtime:2.0.0"
implementation "androidx.lifecycle:lifecycle-extensions:2.0.0"
kapt "androidx.lifecycle:lifecycle-compiler:2.0.0"
复制代码

然后将Dao层抽象方法的返回值改成LiveData<T>

@Dao
abstract class UserDao {

    @Query("select * from tab_user")
    abstract fun getAll(): LiveData<List<User>>
}
复制代码

在activity中的使用如下

class RoomActivity : AppCompatActivity() {
	...
    private fun loadUser() {
        AppDataBase.getInstance().userDao().getAll().observe(this, Observer {
            adapter!!.data = it
        })
    }
    ...
}
复制代码

UserDaogetAll()方法返回的是一个RoomTrackingLiveData(继承LiveData)对象, 当你调用observe方法的时候, 会在LiveDataonActive()回调中执行查询操作,会使用AppDataBaseQueryExecutor(默认是大小为4的线程池)对象在子线程中执行查询操作,查询完成之后,会通过LiveDatapostValue(value)方法将结果在主线程中通知到你的Observer回调

由于LiveDataobserve会绑定Activity的生命周期,所以它还有一个优势是 只会在界面可见的时候才会把数据回调给你 去刷新ui

如果你不需要绑定activity生命周期,可调用observeForever()方法

AppDataBase.getInstance().userDao().getAll().observeForever {
    adapter!!.data = it
}
复制代码

如果你关心结合MVVM的具体用法,请参考googlesamplesandroid-architecture-componentsBasicSample项目

结合rxjava2

首先添加rxjava2需要的相关依赖

implementation "androidx.room:room-rxjava2:2.1.0"
implementation "io.reactivex.rxjava2:rxjava:2.2.10"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
复制代码

然后将Dao层抽象方法的返回值改成Flowable<T>

@Dao
abstract class UserDao {

    @Query("select * from tab_user")
    abstract fun getAll(): Flowable<List<User>>
}
复制代码

在activity中的使用如下

class RoomActivity : AppCompatActivity() {
	...
    AppDataBase.getInstance().userDao().getAll()
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe({
            adapter!!.data = it
        }, {
            Log.i("TAG", "error")
        })
    ...
}
复制代码

结合rxjava2使用也不需要手动创建子线程去执行查询操作,只需要将返回值定义成Flowable,当执行subscribe方法的时候,里面会自动使用AppDataBaseQueryExecutor(默认是大小为4的线程池)对象在子线程中执行查询操作,然后通知给观察者,由于使用了observeOn指定了观察者的回调线程是在主线程,所以最后的回调在主线程中

如果你对rxjava非常了解,相信结合rxjava的各种操作符,会更加方便你处理更加复杂的业务场景

详细的结合rxjava2的用法,请参考googlesamplesandroid-architecture-componentsBasicRxJavaSampleKotlin项目和BasicRxJavaSample项目

结合guava

首先添加guava需要的相关依赖

implementation "androidx.room:room-guava:2.1.0"
implementation "com.google.guava:guava:28.0-android"
复制代码

然后将Dao层抽象方法的返回值改成ListenableFuture<T>

@Dao
abstract class UserDao {

    @Query("select * from tab_user")
    abstract fun getAll(): ListenableFuture<List<User>>
}
复制代码

在activity中的使用如下

class RoomActivity : AppCompatActivity() {
	...
    Futures.addCallback(AppDataBase.getInstance().userDao().getAll(), object: FutureCallback<List<User>> {
        override fun onSuccess(result: List<User>?) {
            runOnUiThread {
                adapter!!.data = result!!
            }
        }

        override fun onFailure(t: Throwable) {

        }
    }, MoreExecutors.directExecutor())
    ...
}
复制代码

结合guava使用也是会使用AppDataBaseQueryExecutor(默认是大小为4的线程池)对象在子线程中执行查询操作,通过使用FuturesaddCallback的静态方法添加 FutureCallback回调 获取查询结果,但是由于没办法直接指定在主线程中执行回调,所以必须手动调用runOnUiThread方法在主线程刷新ui