RxJava2 просто метод - как запустить вставку комнаты в другой поток?

у меня есть метод вставки базы данных комнаты, который выглядит следующим образом:

@Dao
public interface CountriesDao{

    @Insert(onConflict = REPLACE)
    List<Long> addCountries(List<CountryModel> countryModel);
}

Я понимаю, что это не может работать в главном потоке. Вот как я определяю свою базу данных:

Room.inMemoryDatabaseBuilder(context.getApplicationContext(), MyDatabase.class).build();

Я пытаюсь использовать 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");
            }
        });
    }

для меня это явно работает в другом потоке. Не основной поток, но когда я запускаю этот код, я получаю следующее ошибка:

полная трассировка стека ниже. Почему это происходит ?

процесс: com.мобильный.приложение myapp.постановка, PID: 12990
Ява.ленг.IllegalStateException: фатальное исключение, брошенное на планировщик. Вызвано: java.ленг.IllegalStateException: не удается получить доступ к базе данных основной поток, поскольку он потенциально может заблокировать пользовательский интерфейс в течение длительного периода времени. на Ио.реактивекс.андроид.планировщики.HandlerScheduler $ ScheduledRunnable.run (HandlerScheduler.java: 111) на Андроид.ОС.Обработчик.handleCallback (обработчик.java: 751) на Андроид.ОС.Обработчик.dispatchMessage(обработчика.java: 95) на андроид.ОС.Петлитель.петля (Looper.java: 154) на Андроид.приложение.ActivityThread.main (ActivityThread.java: 6077) на Яве.ленг.отражать.Метод.invoke (собственный метод) на com.андроид.внутренний.ОС.ZygoteInit$MethodAndArgsCaller.беги(Зайготейнит.java: 866) по ком.андроид.внутренний.ОС.Зиготейнит.main (ZygoteInit.java: 756) Вызвано: java.ленг.IllegalStateException: не удается получить доступ к базе данных основной поток, поскольку он потенциально может заблокировать пользовательский интерфейс в течение длительного периода времени. на андроид.арка.стойкость.комната.RoomDatabase.assertNotMainThread (RoomDatabase.java: 138) на андроид.арка.стойкость.комната.RoomDatabase.beginTransaction (RoomDatabase.java: 185) на com.мобильный.приложение myapp.данные.комната.Дао.CountriesDao_Impl.addCountries (CountriesDao_Impl.java: 165) на com.мобильный.приложение myapp.данные.хранилища.CountryRepository.storeCountries (CountryRepository.java: 42) на com.мобильный.приложение myapp.ПОЛЬЗОВАТЕЛЬСКИЙ ИНТЕРФЕЙС.ПМК.Предъявители.SignUpPresenter.cacheCountries (SignUpPresenter.java: 40) на com.мобильный.приложение myapp.ПОЛЬЗОВАТЕЛЬСКИЙ ИНТЕРФЕЙС.ПМК.Предъявители.SignUpPresenter$CountriesSubscriber.onNext (SignUpPresenter.java: 60) на com.мобильный.приложение myapp.ПОЛЬЗОВАТЕЛЬСКИЙ ИНТЕРФЕЙС.ПМК.Предъявители.SignUpPresenter$CountriesSubscriber.onNext (SignUpPresenter.Ява:49) на Ио.реактивекс.внутренний.операторы.заметный.ObservableObserveOn$ObserveOnObserver.drainNormal (ObservableObserveOn.java: 200) на Ио.реактивекс.внутренний.операторы.заметный.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java: 252) на Ио.реактивекс.андроид.планировщики.HandlerScheduler $ ScheduledRunnable.run (HandlerScheduler.java: 109) на Андроид.ОС.Обработчик.handleCallback (обработчик.java: 751)  на Андроид.ОС.Обработчик.dispatchMessage(обработчика.java: 95)  на андроид.ОС.Петлитель.петля (Looper.java: 154)  на Андроид.приложение.ActivityThread.main (ActivityThread.java: 6077)  на Яве.ленг.отражать.Метод.invoke (собственный метод)  на com.андроид.внутренний.ОС.ZygoteInit$MethodAndArgsCaller.беги(Зайготейнит.java: 866)  по ком.андроид.внутренний.ОС.Зиготейнит.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();
    }
  }
}

4 ответов


Это распространенная ошибка: just() не выполнять "код" в скобках как just принимает значение, а не вычисление. Вам нужно fromCallable:

Observable.fromCallable(() -> db.countriesDao().addCountries(countriesList))

еще лучше, вы можете использовать Completable. Описание: представляет вычисление без какого-либо значения, но только индикация завершения или исключение.

Completable.fromAction(() -> db.countriesDao().addCountries(list));

Примечание: номер не поддерживает доступ к базе данных в основном потоке, если вы вызвали allowMainThreadQueries() в построителе, потому что это может блокировка пользовательского интерфейса в течение длительного периода времени. Асинхронные запросы-запросы что возвращаемые экземпляры LiveData или Flowable освобождаются от этого правило, поскольку они асинхронно выполняют запрос в фоновом потоке когда нужно.

таким образом, ваш код может быть таким

Completable.fromAction(() -> db.countriesDao()
                .addCountries(list))
                .subscribeOn(Schedulers.io())
                .subscribe();

вы также можете использовать один заметный

        Single.create(new SingleOnSubscribe<List<Long>>() {
        @Override
        public void subscribe(SingleEmitter<List<Long>> emitter) throws Exception {
            try {
                List<Long> ids = db.countriesDao().addCountries(countriesList);
                emitter.onSuccess(ids);
            } catch (Throwable t) {
                emitter.onError(t);
            }
        }})
    .observeOn(AndroidSchedulers.mainThread())
    .subscribeOn(Schedulers.io())
    .subscribeWith(new DisposableSingleObserver<Long>() {
        @Override
        public void onSuccess(List<Long> ids) {

        }

        @Override
        public void onError(Throwable e) {

        }
});