📌  相关文章
📜  如何将 Room 与 LiveData 一起使用?

📅  最后修改于: 2022-05-13 01:58:44.074000             🧑  作者: Mango

如何将 Room 与 LiveData 一起使用?

在之前的文章中,我们讨论了如何在 Android 应用程序中使用 Room 持久性库以及 Room 内部是如何工作的。我们还谈到了我们可以在 Room 的帮助下执行的各种操作。其中之一是将 LiveData 与 Room 一起使用。该房间允许简单集成 LiveData。你只需要从你的 DAO 方法中返回 LiveData,剩下的就交给 Room。

LiveData 可观察查询

运行查询时,您经常希望应用程序的 UI 在数据更改时自动更新。在查询方法描述中使用 LiveData 类型的返回值来完成此操作。

Kotlin
@Dao
interface Course {
    @Query("SELECT * FROM courses")
    fun getAllLiveData(): LiveData>
}


Kotlin
@Override
public LiveData> getAllLiveData() {
  final String _sql = "SELECT * FROM course";
  final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
  return __db.getInvalidationTracker().createLiveData(new String[]{"course"}, false, new Callable>() {
      
    @Override
    public List 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 _result = new ArrayList(_cursor.getCount());
        while(_cursor.moveToNext()) {
          final GFG _item;
          final int _tmpUid;
          _tmpUid = _cursor.getInt(_cursorIndexOfUid);
          final String _courseName;
          _courseName = _cursor.getString(_cursorIndexOfFirstName);
          final String _coursePrice;
          _coursePrice = _cursor.getString(_cursorIndexOfLastName);
          _item = new GFG(_tmpUid,_courseName,_coursePrice);
          _result.add(_item);    
        }
        return _result;
      } finally {
        _cursor.close();
      }
    }
  
    @Override
    protected void finalize() {
      _statement.release();
    }
  });
}


Kotlin
@Dao
interface GFGDao {
    
    @Query("SELECT * from courses where uid = :id LIMIT 1")
    fun loadGFGById(id: Int): Flowable
  
    @Insert
    fun insertCourses(vararg courses: GFG): Completable
  
    @Delete
    fun deleteAllCourses(courses: List): Single
    
}


Kotlin
@Override
public Completable insertLargeNumberOfGFGs(final GFG... GFGs) {
  return Completable.fromCallable(new Callable() {
    @Override
    public Void call() throws Exception {
      __db.beginTransaction();
      try {
        __insertionAdapterOfGFG.insert(GFGs);
        __db.setTransactionSuccessful();
        return null;
      } finally {
        __db.endTransaction();
      }
    }
  });
}
  
@Override
public Single deleteAllGFGs(final List GFGs) {
  return Single.fromCallable(new Callable() {
    @Override
    public Integer call() throws Exception {
      int _total = 0;
      __db.beginTransaction();
      try {
        _total +=__deletionAdapterOfGFG.handleMultiple(GFGs);
        __db.setTransactionSuccessful();
        return _total;
      } finally {
        __db.endTransaction();
      }
    }
  });
}
  
@Override
public Flowable loadGFGById(final int courseID) {
  final String _sql = "SELECT * from GFGs where uid = ? LIMIT 1";
  final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
  int _argIndex = 1;
  _statement.bindLong(_argIndex, courseID);
  return RxRoom.createFlowable(__db, false, new String[]{"GFGs"}, new Callable() {
    @Override
    public GFG call() throws Exception {
      // Some exception Handling magic
    }
  
    @Override
    protected void finalize() {
      _statement.release();
    }
  });
}


Kotlin
@Dao
interface GFGDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertGFG(vararg course: GFG)    @Update
    suspend fun updateGFG(vararg course: GFG)    @Delete
    suspend fun deleteGFG(vararg course: GFG)    @Query("SELECT * FROM course")
    suspend fun loadAllGFG(): Array
}


Kotlin
@Override
public Object insertGFG(final Course[] GFG, final Continuation p1) {
  return CoroutinesRoom.execute(__db, true, new Callable() {
    @Override
    public Unit call() throws Exception {
      __db.beginTransaction();
      try {
        __insertionAdapterOfCourse.insert(GFG);
        __db.setTransactionSuccessful();
        return Unit.INSTANCE;
      } finally {
        __db.endTransaction();
      }
    }
  }, p1);
}


更新数据库时,Room 会生成更新 LiveData 所需的所有代码。生成的代码如下所示:

科特林

@Override
public LiveData> getAllLiveData() {
  final String _sql = "SELECT * FROM course";
  final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
  return __db.getInvalidationTracker().createLiveData(new String[]{"course"}, false, new Callable>() {
      
    @Override
    public List 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 _result = new ArrayList(_cursor.getCount());
        while(_cursor.moveToNext()) {
          final GFG _item;
          final int _tmpUid;
          _tmpUid = _cursor.getInt(_cursorIndexOfUid);
          final String _courseName;
          _courseName = _cursor.getString(_cursorIndexOfFirstName);
          final String _coursePrice;
          _coursePrice = _cursor.getString(_cursorIndexOfLastName);
          _item = new GFG(_tmpUid,_courseName,_coursePrice);
          _result.add(_item);    
        }
        return _result;
      } finally {
        _cursor.close();
      }
    }
  
    @Override
    protected void finalize() {
      _statement.release();
    }
  });
}

__db.getInvalidationTracker() 用于前面的代码()。 createLiveData() 接受一个 tableNames 数组、inTransaction 布尔标志和一个可调用的 computeFunction。

  1. inTransaction 参数指定查询是否必须作为事务执行。
  2. computeFunction 是一个可调用的,只要观察到的表发生变化就会调用它。

我们还可以看到,computeFunction 的 call() 方法执行了实际的查询执行。每当观察者开始观察 LiveData 或观察到的表中发生任何更改时,都会调用它。

RxJava 的房间

在之前的文章中,我们讨论了如何在 Android 应用程序中使用 Room 持久性库。我们还讨论了 Room DAO 可以执行的各种操作。使用 Room,使用 RxJava 可观察对象变得轻而易举。我们需要在构建中包含以下依赖项,以从您的 DAO 方法返回 RxJava 可观察对象。

首先,毕业:

dependencies {
  def room_version = "2.2.5"
  implementation "androidx.room:room-runtime:$room_version"
  kapt "androidx.room:room-compiler:$room_version"
  // Geeks for Geeks RxJava support for Room
  implementation "androidx.room:room-rxjava2:$room_version"
}

RxJava Room 的响应式查询包括以下对 RxJava2 类型返回值的支持:

  1. @Query 方法: Room 接受 Publisher、Flowable 和 Observable 返回值。
  2. @Insert、@Update 和 @Delete 方法:Room 2.1.0 和更高版本支持 Completable、 类型的返回值。

科特林

@Dao
interface GFGDao {
    
    @Query("SELECT * from courses where uid = :id LIMIT 1")
    fun loadGFGById(id: Int): Flowable
  
    @Insert
    fun insertCourses(vararg courses: GFG): Completable
  
    @Delete
    fun deleteAllCourses(courses: List): Single
    
}

以下是如何将这些方法付诸实践的示例

科特林

@Override
public Completable insertLargeNumberOfGFGs(final GFG... GFGs) {
  return Completable.fromCallable(new Callable() {
    @Override
    public Void call() throws Exception {
      __db.beginTransaction();
      try {
        __insertionAdapterOfGFG.insert(GFGs);
        __db.setTransactionSuccessful();
        return null;
      } finally {
        __db.endTransaction();
      }
    }
  });
}
  
@Override
public Single deleteAllGFGs(final List GFGs) {
  return Single.fromCallable(new Callable() {
    @Override
    public Integer call() throws Exception {
      int _total = 0;
      __db.beginTransaction();
      try {
        _total +=__deletionAdapterOfGFG.handleMultiple(GFGs);
        __db.setTransactionSuccessful();
        return _total;
      } finally {
        __db.endTransaction();
      }
    }
  });
}
  
@Override
public Flowable loadGFGById(final int courseID) {
  final String _sql = "SELECT * from GFGs where uid = ? LIMIT 1";
  final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 1);
  int _argIndex = 1;
  _statement.bindLong(_argIndex, courseID);
  return RxRoom.createFlowable(__db, false, new String[]{"GFGs"}, new Callable() {
    @Override
    public GFG call() throws Exception {
      // Some exception Handling magic
    }
  
    @Override
    protected void finalize() {
      _statement.release();
    }
  });
}

我们可以从自动生成的代码中看到 Room 使用 fromCallable()运算符创建了 Completable 和 Single 。在 RxRoom。 createFlowable, Room 使用 Flowable 要创建 Flowable,请使用 create()。 callable 的 call() 方法中的代码类似于非响应式实现。

房间中的 Kotlin 协程

在之前的文章中,我们讨论了 Room 持久性库以及使用它的好处。使用 Room 的好处之一是它可以很容易地与其他库集成,例如 Kotlin Coroutines。那么让我们来谈谈如何在 Room 的帮助下做到这一点。首先,我们必须为 Kotlin 协程支持添加以下依赖项:

dependencies {
  def room_version = "2.2.5"

  implementation "androidx.room:room-runtime:$room_version"
  kapt "androidx.room:room-compiler:$room_version"  
  // Basic extension for Kotlin to make Room work
  implementation "androidx.room:room-ktx:$room_version"
}

Kotlin 协程可用于编写异步方法

您可以使用暂停 Kotlin 关键字来使用 Kotlin 协程使您的 DAO 方法异步。这可以防止它们在主线程上执行。

科特林

@Dao
interface GFGDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertGFG(vararg course: GFG)    @Update
    suspend fun updateGFG(vararg course: GFG)    @Delete
    suspend fun deleteGFG(vararg course: GFG)    @Query("SELECT * FROM course")
    suspend fun loadAllGFG(): Array
}

上面列出的所有方法都是由 Room 实现的。挂起函数的实现与非挂起函数的实现非常相似。

科特林

@Override
public Object insertGFG(final Course[] GFG, final Continuation p1) {
  return CoroutinesRoom.execute(__db, true, new Callable() {
    @Override
    public Unit call() throws Exception {
      __db.beginTransaction();
      try {
        __insertionAdapterOfCourse.insert(GFG);
        __db.setTransactionSuccessful();
        return Unit.INSTANCE;
      } finally {
        __db.endTransaction();
      }
    }
  }, p1);
}

结论

两种实现的唯一区别在于,在挂起函数的情况下,CoroutinesRoom.execute 负责停止执行流程。这就是将 Room 与 LiveData、RxJava 和 Kotlin 协程一起使用。我们希望您发现这篇 Geeks for Geeks 文章很有趣。