【问题标题】:Executing delete with room (rxjava)使用房间执行删除(rxjava)
【发布时间】:2017-12-21 08:55:32
【问题描述】:

在房间里,@Delete 注释不会发出任何东西。这就是dao 的样子

@Dao
public interface UserDao {
    @Delete
    void deleteUser(User user);
    //We can't use Maybe or Single or anything here

}

这在做类似的事情时会成为一个问题

userRepository.deleteUser().subscribeOn 因为我们没有来自dao 的发射。我使用以下代码在后台线程上调用 deleteUser。

Observable.just(appDatabase).
            subscribeOn(SchedulerProvider.getInstance().computation()).

            subscribe(db -> {
                userRepository.logoutUser(loggedUser.getLoggedInUser());
                loggedUser.setLoggedInUser(null);


            }, this::handleError);

这很好用。但是,在 subscribe 方法中,我现在需要访问 Android UI 以显示一个宣布删除成功的 toast。自然,我得到了这个异常(因为链中缺少 observeOn)

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

但是当我把observeOn 像这样放

Observable.just(appDatabase).
        subscribeOn(SchedulerProvider.getInstance().computation()).
        observeOn(SchedulerProvider.getInstance().ui()).
        subscribe(db -> {
            userRepository.logoutUser(loggedUser.getLoggedInUser());
            loggedUser.setLoggedInUser(null);

            Message message = new Message(R.string.user_logged_out_msg);
            message.setMessageType(Message.MessageType.SUCCESS_MESSAGE);
            view.showMessages(Arrays.asList(message)); //this leads to a taost

        }, this::handleError);

我奇怪地得到了这个异常:

cannot access database on the main thread since it may potentially lock the UI for a long period of time.

【问题讨论】:

  • 虽然我没有给你一个明确的答案,但我可以说 Room 默认在后台线程上调用它的 RXJava,所以你不需要显式调用 subscibeOn() 但你确实需要确保您调用观察以将活动推送到 UI 线程。如果我是你,这就是我会关注的区域。
  • “我使用下面的代码在后台线程上调用 deleteUser”——你没有调用 deleteUser()。您可能希望同步您的示例,以使它们保持一致。

标签: android rx-java2 rx-android android-room


【解决方案1】:

根据来自这个问题的信息:Run Void Method in Background (StackOverflow)

使用 Completable 并订阅另一个线程,如下所示:

Completable.fromAction(this::clearCachedData)
   .subscribeOn(Schedulers.io())
   .subscribe();

为我工作。 clearCachedData 方法在我正在调用的 Room 中执行查询。

我的查询是:

/**
 * Delete all data in the items table.
 */
@Query("DELETE FROM items")
void deleteWeatherItems();

【讨论】:

    【解决方案2】:

    我知道这已经晚了。但是我遇到了同样的问题,并且能够通过以下方式解决它

    在道课中

    @Query("DELETE FROM users")
        fun deleteAllUser()
    

    这样称呼它。这样你就可以订阅,它会在后台运行。

    Single.fromCallable {
            user.deleteAllUser() //User Dao fun
        }
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(..do stuff..)
    

    【讨论】:

    • Single.fromCallable 期望返回一个值。而且你不能返回 null 因为它与io.reactivex.exceptions.OnErrorNotImplementedException: The callable returned a null value 崩溃
    • @HughHughTeotl 它返回 Unit,而不是 null。
    【解决方案3】:

    将 Observable just 方法替换为 create

      Observable.create(new ObservableOnSubscribe<Object>() {
                @Override
                public void subscribe(@io.reactivex.annotations.NonNull ObservableEmitter<Object> e) throws Exception {
                    e.onNext(tileDatabase.getCategoryDeo().deleteCategory(category));
    
                }
            })
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer<Object>() {
                        @Override
                        public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
                        }
    
                        @Override
                        public void onNext(@io.reactivex.annotations.NonNull Object o) {
                            Toast.makeText(MainActivity.this, "Record deleted ", Toast.LENGTH_SHORT).show();
                        }
    
                        @Override
                        public void onError(@io.reactivex.annotations.NonNull Throwable e) {
                        }
    
                        @Override
                        public void onComplete() {
                        }
                    });
    

    【讨论】:

    • 这看起来很合理。稍后我会试一试。
    【解决方案4】:

    尝试将用户列表传递给删除函数,并返回已删除用户的数量(代码在 Kotlin 中)。

    @Dao
    public interface UserDao {
        ...
    
        @Delete
        fun deleteUsers(users: List<User>): Int
    }
    

    这将是数据库类:

    @Database(entities = [User::class], version = 1)
    abstract class UsersDatabase : RoomDatabase() {
    
        abstract fun userDao(): UserDao
    
        companion object {
            private var INSTANCE: UsersDatabase? = null
    
            fun getInstance(context: Context): UsersDatabase? {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.applicationContext, UsersDatabase::class.java, "my_database.db").build()
                }
                return INSTANCE
            }
    
            ...
    }
    

    还有这些存储库和 viewModel(Room Android 架构):

    class UsersRepository internal constructor(val application: Application) {
    
       private val userDao: UserDao = UsersDatabase.getInstance(application)!!.userDao()
    
       ...
    
       fun deleteUsers(users: List<User>): Single<Int> {
            return Single.fromCallable { userDao.deleteUsers(users) }
        }
    }
    
    
    class UsersViewModel(val app: Application) : AndroidViewModel(app) {
        private val repo: UsersRepository = UsesRepository(application = app)
        ...
    
        fun deleteUsers(users: List<User>): Single<Int> {
            return repo.deleteUsers(users).subscribeOn(Schedulers.io())
        }
    }
    

    然后在一些活动或片段中:

    class UsersActivity : AppCompatActivity() {
    
        private lateinit var viewModel: UsersViewModel
        ...
    
        override fun onCreate(savedInstanceState: Bundle?) {
        ...
           viewModel = ViewModelProviders.of(this).get(UsersViewModel::class.java)
        }
    
        fun removeUsers(users: List<User>) {
           ...
           viewModel.deleteUsers(users).subscribe(this::toast)
        }
        ...
    
        fun toast() {
            Toast.make(this, "Users deleted", Toast.LENGTH_SHORT).show
        }
    }
    

    【讨论】:

      【解决方案5】:
      @Query("DELETE FROM User.TABLE_NAME")
      public void nukeTable();
      
      @Query("DELETE FROM " + User.TABLE_NAME + " WHERE " + User.COLUMN_ID + " = :id")
      int deleteById(long id);
      

      这些方法可能很有用。

      【讨论】:

      • 如何用 rx java 处理它
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多