如何在后台线程执行Room Dao方法获取整型返回值?
嘿,看你的代码片段,应该是想用RxJava来后台执行Room的计数查询,但用Completable是不对的——它是用来执行没有返回值的任务的,而你需要获取查询的结果。我给你两个靠谱的实现方案,一个是用RxJava的正确姿势,另一个是现在Jetpack更推荐的Coroutines方式,你可以按需选择:
方案一:用RxJava实现(适配你原来的思路)
首先得修改你的Dao方法,让它返回Single<Integer>而不是直接返回int,这样RxJava才能帮你处理异步和返回值:
@Dao public interface PhotosDao { @Query("SELECT COUNT(*) FROM photos") Single<Integer> getPersistedPhotosSize(); }
然后在Repository里,你只需要返回这个Single,再指定执行线程就好:
public Single<Integer> getNumRowsFromFeed() { // 让查询在IO线程执行,可选切换回主线程处理结果 return photosDao.getPersistedPhotosSize() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); }
调用的时候,你就能拿到返回的计数,判断是否为0了:
// 在ViewModel或者Presenter里调用 repository.getNumRowsFromFeed() .subscribe(rowCount -> { if (rowCount == 0) { // 本地没有存储照片,执行对应的逻辑 } else { // 有照片,执行其他逻辑 } }, throwable -> { // 处理查询异常,比如数据库操作失败 Log.e("PhotoRepo", "Failed to get photo count", throwable); });
注意:记得用CompositeDisposable管理你的订阅,在页面销毁时取消,避免内存泄漏。
方案二:用Coroutines实现(Jetpack推荐,更简洁)
现在Google更推荐用Coroutines来处理异步任务,Room本身也支持挂起函数,写法会更简洁:
首先修改Dao方法,加上suspend关键字:
@Dao interface PhotosDao { @Query("SELECT COUNT(*) FROM photos") suspend fun getPersistedPhotosSize(): Int }
然后在Repository里定义一个挂起函数:
class PhotosRepository(private val photosDao: PhotosDao) { suspend fun getNumRowsFromFeed(): Int { // Room会自动在后台线程执行挂起的Dao方法 return photosDao.getPersistedPhotosSize() } }
最后在ViewModel里用viewModelScope来调用(避免内存泄漏):
class PhotosViewModel(private val repository: PhotosRepository) : ViewModel() { fun checkLocalPhotoCount() { viewModelScope.launch { val rowCount = repository.getNumRowsFromFeed() if (rowCount == 0) { // 本地无照片的逻辑 } } } }
如果你需要实时监听本地照片数量的变化,还可以让Dao返回Flow<Int>,这样数据更新时会自动通知你:
@Dao interface PhotosDao { @Query("SELECT COUNT(*) FROM photos") fun getPersistedPhotosSizeFlow(): Flow<Int> }
Repository里直接返回这个Flow:
fun getPhotoCountFlow(): Flow<Int> { return photosDao.getPersistedPhotosSizeFlow() }
ViewModel里可以直接观察这个Flow:
val photoCount = repository.getPhotoCountFlow() .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), 0)
为啥你原来的方式有问题?
你用Completable的话,它没有返回值,只能执行动作,没法拿到查询结果;而且用数组捕获变量的方式不仅不优雅,还可能有线程安全问题,完全没必要——RxJava的Single或者Coroutines的挂起函数都能完美解决这个问题。
内容的提问来源于stack exchange,提问作者lounah

