Rxjava2只是方法 - 如何在另一个线程上运行房间插入?

j2e*_*nue 18 android rx-java android-room

我有一个房间持久数据库插入方法,如下所示:

@Dao
public interface CountriesDao{

    @Insert(onConflict = REPLACE)
    List<Long> addCountries(List<CountryModel> countryModel);
}
Run Code Online (Sandbox Code Playgroud)

我意识到这不能在主线程上运行.以下是我定义数据库的方法:

Room.inMemoryDatabaseBuilder(context.getApplicationContext(), MyDatabase.class).build();
Run Code Online (Sandbox Code Playgroud)

我试图使用rxjava2,以便我不在主线程上运行.我创建了以下方法:

public void storeCountries(List<CountryModel> countriesList) {
        Observable.just(db.countriesDao().addCountries(countriesList))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new DefaultSubscriber<List<Long>>(){
            @Override
            public void onSubscribe(@NonNull Disposable d) {
                super.onSubscribe(d);
            }

            @Override
            public void onNext(@NonNull List<Long> longs) {
                super.onNext(longs);
                Timber.d("insert countries transaction complete");
            }

            @Override
            public void onError(@NonNull Throwable e) {
                super.onError(e);
                Timber.d("error storing countries in db"+e);
            }

            @Override
            public void onComplete() {
                Timber.d("insert countries transaction complete");
            }
        });
    }
Run Code Online (Sandbox Code Playgroud)

对我来说,这显然是在另一个线程上运行.不是主线程,但是当我运行此代码时,我收到以下错误:

完整的堆栈跟踪如下.为什么会这样?

进程:com.mobile.myapp.staging,PID:12990
java.lang.IllegalStateException:调度程序抛出致命异常.引起:java.lang.IllegalStateException:无法访问主线程上的数据库,因为它可能会长时间锁定UI.at io.reactivex.android.schedulers.HandlerScheduler $ ScheduledRunnable.run(HandlerScheduler.java:111)android.os.Handler.handleCallback(Handler.java:751)android.os.Handler.dispatchMessage(Handler.java:95) )在android.app.Looper.loop(Looper.java:154)的android.app.ActivityThread.main(ActivityThread.java:6077),位于com.android的java.lang.reflect.Method.invoke(Native Method). internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:866)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)引起:java.lang.IllegalStateException:无法访问主数据库线程,因为它可能会长时间锁定UI.在android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:138)的android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:185)com.mobile.myapp.data.room.dao .countriesDao_Impl.addCountries(CountriesDao_Impl.java:165)at com.mobile.myapp.data.repositories.CountryRepository.storeCountries(CountryRepository.java:42)at com.mobile.myapp.UI.mvp.Presenters.SignUpPresenter.cacheCountries(SignUpPresenter) .java:40)at com.mobile.myapp.UI.mvp.Presenters.SignUpPresenter $ CountriesSubscriber.onNext(SignUpPresenter.java:60)at com.mobile.myapp.UI.mvp.Presenters.SignUpPresenter $ CountriesSubscriber.onNext(SignUpPresenter) .java:49)at io.reactivex.internal.operators.observable.ObservableObserveOn $ ObserveOnObserver.drainNormal(ObservableObserveOn.java:200)at io.reactivex.internal.operators.observable.ObservableObserveOn $ ObserveOnObserver.run(ObservableObserveOn.java:252 )在io.reactivex.android.schedulers.HandlerScheduler $ ScheduledRunnable.run(HandlerSch)eduler.java:109)android.os.Handler.handleCallback(Handler.java:751)android.os.Handler.dispatchMessage(Handler.java:95)android.os.Looper.loop(Looper.java:154) )在android.app.ActivityThread.main(ActivityThread.java:6077)at java.lang.reflect.Method.invoke(Native Method)at com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:866) )在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)

不重要但如果你需要知道defaultSubscriber类在这里是什么样子,它是:

DefaultSubscriber.java

public class DefaultSubscriber<T> implements Observer<T> {

Disposable disposable;

@Override
public void onSubscribe(@NonNull Disposable d) {
    disposable = d;
}

@Override
public void onNext(@NonNull T t) {

}

@Override
public void onError(@NonNull Throwable e) {
    Timber.e(e);
}

@Override
public void onComplete() {

}

public void unsubscribe(){
    if(disposable!=null && !disposable.isDisposed()){
        disposable.dispose();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

aka*_*okd 30

这是一个常见的错误:just()不会在其括号内执行"代码",因为just它取值而不是计算.你需要fromCallable:

Observable.fromCallable(() -> db.countriesDao().addCountries(countriesList))
Run Code Online (Sandbox Code Playgroud)

  • 一个可调用的函数自动在另一个线程上运行,而我不必调用subscribeOn(Schedulers.io())? (2认同)

dyn*_*tem 15

更好的是,你可以用一个Completable.其描述:表示没有任何值的计算,但仅表示完成或异常.

Completable.fromAction(() -> db.countriesDao().addCountries(list));
Run Code Online (Sandbox Code Playgroud)


Lev*_*yan 10

注意:Room不支持在主线程上进行数据库访问,除非您在构建器上调用了allowMainThreadQueries(),因为Room可能会长时间锁定UI。异步查询-返回LiveData或Flowable实例的查询不受此规则的限制,因为它们在需要时在后台线程上异步运行查询。

所以你的代码可以像这样

Completable.fromAction(() -> db.countriesDao()
                .addCountries(list))
                .subscribeOn(Schedulers.io())
                .subscribe();
Run Code Online (Sandbox Code Playgroud)


Pha*_*inh 5

从房间里2.1.0-alpha02,你可以在插入时使用 ( Completeable, Single, Maybe) ( https://medium.com/androiddevelopers/room-rxjava-acb0cd4f3757 )

例子

@Dao
interface UserDao{
     @Insert
     Completable insert(final User user); // currently, we must put final before user variable or you will get error when compile
}
Run Code Online (Sandbox Code Playgroud)

使用

db.userDao().insert(user).subscribeOn(Schedulers.io()).subscribe(new Action() {
    @Override
    public void run() throws Exception {
        // success
    }
}, new Consumer < Throwable > () {
    @Override
    public void accept(Throwable throwable) throws Exception {
        // error
    }
});
Run Code Online (Sandbox Code Playgroud)