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) {
}
});