Jetpack Room入门系列:(一)基本介绍
Jetpack Room入门系列:(二)使用DAO读写数据库
Jetpack Room入门系列:(三)实体/数据表关系
Jetpack Room入门系列:(四)内部实现原理
Jetpack Room入门系列:(五)数据库版本升级、数据迁移
Jetpack Room入门系列:(六)配合LiveData等三方库的使用
作为Jetpack生态的成员,Room可以很好地兼容Jetpack的其他组件以及ACC推荐的三方库,例如LiveData、RxJava等。
使用LiveData
DAO可以定义LiveData类型的结果,Room内部兼容了LiveData的响应式逻辑。
可观察的查询
通常的Query需要命令式的获取结果,LiveData可以让结果的更新可被观察(Observable Queries)。
@Dao
interface UserDao {
@Query("SELECT * FROM users")
fun getAllLiveData(): LiveData<List<User>>
}
当DB的数据发生变化时,Room会更新LiveData:
@Override
public LiveData<List<User>> getAllLiveData() {
final String _sql = "SELECT * FROM users";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
return __db.getInvalidationTracker().createLiveData(new String[]{
"users"}, false, new Callable<List<User>>() {
@Override
public List<User> call() throws Exception {
final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
try {
final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
final int _cursorIndexOfFirstName = CursorUtil.getColumnIndexOrThrow(_cursor, "first_name");
final int _cursorIndexOfLastName = CursorUtil.getColumnIndexOrThrow(_cursor, "last_name");
final List<User> _result = new ArrayList<User>(_cursor.getCount());
while(_cursor.moveToNext()) {
final User _item;
final int _tmpUid;
_tmpUid = _cursor.getInt(_cursorIndexOfUid);
final String _tmpFirstName;
_tmpFirstName = _cursor.getString(_cursorIndexOfFirstName);
final String _tmpLastName;
_tmpLastName = _cursor.getString(_cursorIndexOfLastName);
_item = new User(_tmpUid,_tmpFirstName,_tmpLastName);
_result.add(_item);
}
return _result;
} finally {
_cursor.close();
}
}
@Override
protected void finalize() {
_statement.release();
}
});
}
__db.getInvalidationTracker().createLiveData()
接受3个参数
- tableNames:被观察的表
- inTransaction:查询是否基于事务
- computeFunction:表记录变化时的回调
computeFunction的call中执行真正的sql查询。当Observer首次订阅LiveData时,或者表数据发生变化时,便会执行到这里。
使用RxJava
Room中使用RxJava需要添加以下依赖
dependencies {
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// RxJava support for Room
implementation "androidx.room:room-rxjava2:$room_version"
}
响应式的查询
DAO的返回值类型可以是RxJava2的各种类型:
- @Query注解的方法:返回 Flowable 或 Observable.
- @Insert/@Update/@Delete注解的方法: 返回Completable, Single, and Maybe(Room 2.1.0以上)
@Dao
interface UserDao {
@Query("SELECT * from users where uid = :id LIMIT 1")
fun loadUserById(id: Int): Flowable<User>
@Insert
fun insertUsers(vararg users: User): Completable
@Delete
fun deleteAllUsers(users: List<User>): Single<Int>
}
@Override
public Completable insertLargeNumberOfUsers(final User... users) {
return Completable.fromCallable(new Callable<Void>() {
@Override
public Void call() throws Exception {
__db.beginTransaction();
try {
__insertionAdapterOfUser.insert(users);
__db.setTransactionSuccessful();
return null;
} finally {
__db.endTransaction();
}
}
});
}@Override
public Single<Integer> deleteAllUsers(final List<User> users) {
return Single.fromCallable(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int _total = 0;
__db.beginTransaction();
try {
_total +=__deletionAdapterOfUser.handleMultiple(users);
__db.setTransactionSuccessful();
return _total;
} finally {
__db.endTransaction();
}
}
});
}@Override
public Flowable<User> loadUserById(final int id) {
final String _sql = "SELECT * from users where uid = ? LIMIT 1";
final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
int _argIndex = 1;
_statement.bindLong(_argIndex, id);
return RxRoom.createFlowable(__db, false, new String[]{
"users"}, new Callable<User>() {
@Override
public User call() throws Exception {
//Implementation
}
@Override
protected void finalize() {
_statement.release();
}
});
}
如上,使用fromCallable{…}创建Completable与Single; RxRoom.createFlowable{…}创建Flowable。call()
里执行真正的sql操作
使用协程Coroutine
添加额外依赖:
dependencies {
def room_version = "2.2.5"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version" // Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
}
挂起函数定义DAO
为UserDao中的CURD方法添加suspend
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUsers(vararg users: User)
@Update
suspend fun updateUsers(vararg users: User)
@Delete
suspend fun deleteUsers(vararg users: User)
@Query("SELECT * FROM users")
suspend fun loadAllUsers(): Array<User>
}
CoroutinesRoom.execute
中进行真正的sql语句,并通过Continuation将callback变为Coroutine的同步调用
@Override
public Object insertUsers(final User[] users, final Continuation<? super Unit> p1) {
return CoroutinesRoom.execute(__db, true, new Callable<Unit>() {
@Override
public Unit call() throws Exception {
__db.beginTransaction();
try {
__insertionAdapterOfUser.insert(users);
__db.setTransactionSuccessful();
return Unit.INSTANCE;
} finally {
__db.endTransaction();
}
}
}, p1);
}
可以对比一下普通版本的insertUsers:
@Override
public void insertUsers(final User... users) {
__db.assertNotSuspendingTransaction();
__db.beginTransaction();
try {
__insertionAdapterOfUser.insert(users);
__db.setTransactionSuccessful();
} finally {
__db.endTransaction();
}
}
区别很明显,添加了suspend后,生成代码中会使用CoroutinesRoom.execute
封装协程。