Jetpack Room入门系列:(六)配合LiveData等三方库的使用

在这里插入图片描述
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封装协程。

猜你喜欢

转载自blog.csdn.net/vitaviva/article/details/112746243