web-dev-qa-db-ja.com

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.mobile.myapp.staging、PID:12990
Java.lang.IllegalStateException:スケジューラで致命的な例外がスローされました。原因:Java.lang.IllegalStateException:長時間UIをロックする可能性があるため、メインスレッド上のデータベースにアクセスできません。 io.reactivex.Android.schedulers.HandlerScheduler $ ScheduledRunnable.run(HandlerScheduler.Java:111)at Android.os.Handler.handleCallback(Handler.Java:751)at Android.os.Handler.dispatchMessage(Handler.Java:95) )Android.os.Looper.loop(Looper.Java:154)at 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)at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:756)原因:Java.lang.IllegalStateException:メインのデータベースにアクセスできません潜在的にUIを長時間ロックする可能性があるため。 Android.Arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.Java:138)at Android.Arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.Java:185)at 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)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)io.reactivex.internal.operators.observable.ObservableObserveOn $ ObserveOnObserver.drainNormal(ObservableObserveOn.Java:200)at io.reactivex.internal.operators.observable.ObservableObserveOn $ ObserveOnObserver.run(ObservableObserve.On(Java) )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)Java.lang.reflect.Method.invoke(Native Method)com 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();
    }
  }
}
17
j2emanue

これはよくある間違いです。justは計算ではなく値を取るため、just()は括弧内の「コード」を実行しません。 fromCallableが必要です:

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

さらに良いことに、Completableを使用できます。その説明:値なしの計算を表します完了の指示のみまたは例外

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

注:ビルダーでallowMainThreadQueries()を呼び出さない限り、Roomはメインスレッドでのデータベースアクセスをサポートしません。これは、UIが長時間ロックされる可能性があるためです。非同期クエリ-LiveDataまたはFlowableのインスタンスを返すクエリは、必要に応じてバックグラウンドスレッドで非同期にクエリを実行するため、このルールから除外されます。

あなたのコードは次のようになります

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

部屋から部屋2.1.0-alpha02、挿入時に(CompleteableSingleMaybe)を使用できます( 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
}

を使用して

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
    }
});
3
Phan Van Linh

また、単一のオブザーバブルを使用することもできます

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

        }
});
1
Farid Z