У меня есть тестовый проект с базой данных Room. Используя Asynctask, я могу успешно вставить объект с некоторыми тестовыми данными в базу данных. Я пытаюсь выучить RxJava и заменить Asynctask на RxJava'sobserver, но не получается. Я прочитал много документации и посмотрел учебные пособия, но я не думаю, что совсем понял. Вот соответствующий код:
Здесь я установил свой объект Room с данными из моего List:
for(ObjectForArray item: listToDatabase) {
myRoomEntity.setName( item.getName() );
Log.d( "TAG", myRoomEntity.getName() );
}
Затем я пытаюсь использовать RxJavaObservable для вставки данных в базу данных. Это было изначально и успешно сделано с помощью Asynctask:
Observable<MyRoomEntity> myRX = Observable
.just(myRoomEntity)
.subscribeOn( Schedulers.io() )
.observeOn( AndroidSchedulers.mainThread() );
myRX.subscribe( new Observer<MyRoomEntity>() {
@Override
public void onSubscribe(Disposable d) {
Log.d("TAG ONSUBSCRIBE", d.toString());
try {
myViewModel.insertDatabase( myRoomEntity );
Log.d( "TAG", "Populating database Success" );
}catch(Error error) {
Log.d( "TAG", error.toString() );
}
}
OnNext, OnError и OnComplete пусты.
Когда я запускаю проект, он вылетает с ошибкой:
Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
Очевидно, я неправильно использую RxJava, так как смысл в том, чтобы выполнять асинхронные задачи вне основного потока.





Вы получаете эту ошибку, потому что пытаетесь вставить объект в основной поток (UI).
Вы должны сделать что-то вроде этого:
Observable.fromCallable(() -> myViewModel.insertDatabase( myRoomEntity ))
.subscribeOn( Schedulers.io() )
.observeOn( AndroidSchedulers.mainThread() );
А затем используйте Observer, чтобы подписаться на Observable.
Я предполагаю, что это: myViewModel.insertDatabase(myRoomEntity) - это ваш код вставки. Проверьте ответ еще раз.
Однако, как кажется, вставка ничего не возвращает, вам лучше использовать Completable, а не Observable.
@Alex Хорошо, понял, но часть вставки выдает странную ошибку «не существует экземпляра переменной типа T, так что void соответствует T»
@MarkTornej это потому, что, по-видимому, ваша база данных вставки возвращает пустоту. Вместо этого вы должны использовать Completable.fromAction.
@ror Да, мои данные вставки возвращаются недействительными. Но почему/что он должен возвращать? Он только должен вставлять данные, верно?
Пожалуйста, попробуйте реструктурировать свой код следующим образом:
Completable.fromAction(() -> myViewModel.insertDatabase(myRoomEntity))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(() -> Log.d("TAG", "Populating database Success"),
throwable -> Log.d("TAG", throwable.toString()))
Соображения:
deferhttp://reactivex.io/documentation/operators/defer.htmljust звонковПотрясающий! Это сработало отлично! Большое спасибо @ror за то, что нашли время :)
Однако есть одна вещь. Как запустить метод onComplete? Поскольку у меня нет объекта, я не могу получить метод. Я попытался добавить .onComplete в самом конце, но это не сработало...
О, подождите, добавление .doOnComplete( () -> Log.d("TAG", "COMPLETED" )) перед .subscribe сработало!
На самом деле, первый обработчик действия в блоке подписки является «завершенным» (для наблюдаемого это будет «следующий»). Но да, ваш подход тоже работает.
я использую RX java вместо Asyntask, так как он устарел в Android 9 Android предоставляет несколько замен, таких как Executors, threads, Listenable Futures, Coroutines ?, поэтому вы ищете, как реализовать это с помощью rxjava и как RX Java java помогает вам мигрировать, просто сначала добавьте эти зависимости в gradle.
implementation "io.reactivex.rxjava2:rxjava:2.2.20"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
как только вы импортируете, давайте начнем работать с RX java, я дам вам знать, где вы можете поместить фоновую задачу, предварительно выполнить, после выполнения, например, asynctask
давайте сначала начнем программировать с Rx java, у меня есть комментарий к методу, который поможет вам поместить код
Observable.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
/// here is your background task
return true;
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Boolean>() {
@Override
public void onSubscribe(Disposable d) {
//// pre execute here is my progress dialog
showProgressDialog(getString(R.string.scanning));
}
@Override
public void onNext(Boolean aBoolean) {
//// here is on sucess you can do anystuff here like
if (aBoolean){
/// if its value true you can go ahead with this
}
}
@Override
public void onError(Throwable e) {
/// this helps you to go if there is any error show dialog whatever you wants here
Log.e("error of kind",e.getMessage() );
}
@Override
public void onComplete() {
/// when your task done means post execute
}
});
как только это будет сделано, давайте начнем работу с реализацией
Observable.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
/// here is your background task
uribitmap = getScannedBitmap(original, points);
uri = Utils.getUri(getActivity(), uribitmap);
scanner.onScanFinish(uri);
return true;
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Boolean>() {
@Override
public void onSubscribe(Disposable d) {
//// pre execute here is my progress dialog
showProgressDialog(getString(R.string.scanning));
}
@Override
public void onNext(Boolean aBoolean) {
//// here is on sucess you can do anystuff here like
if (aBoolean){
/// if its value true you can go ahead with this
}
}
@Override
public void onError(Throwable e) {
/// this helps you to go if there is any error show dialog whatever you wants here
Log.e("error of kind",e.getMessage() );
}
@Override
public void onComplete() {
/// when your task done means post execute
uribitmap.recycle();
dismissDialog();
}
});
теперь я сделаю это с исполнителями:
/// pre execute you can trigger to progress dialog
showProgressDialog(getString(R.string.scanning));
ExecutorService executors = Executors.newSingleThreadExecutor();
executors.execute(new Runnable() {
@Override
public void run() {
//// do background heavy task here
final Bitmap uribitmap = getScannedBitmap(original, points);
uri = Utils.getUri(getActivity(), uribitmap);
scanner.onScanFinish(uri);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//// Ui thread work like
uribitmap.recycle();
dismissDialog();
}
});
}
});
О, я вижу. Итак, что такое основной поток и асинхронный поток? Должно быть, запутались в именах. Куда должен идти код
insert?