Как заменить Asynctask на RxJava Observer?

У меня есть тестовый проект с базой данных 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, так как смысл в том, чтобы выполнять асинхронные задачи вне основного потока.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
1 426
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вы получаете эту ошибку, потому что пытаетесь вставить объект в основной поток (UI).

Вы должны сделать что-то вроде этого:

Observable.fromCallable(() -> myViewModel.insertDatabase( myRoomEntity ))
            .subscribeOn( Schedulers.io() )
            .observeOn( AndroidSchedulers.mainThread() );

А затем используйте Observer, чтобы подписаться на Observable.

О, я вижу. Итак, что такое основной поток и асинхронный поток? Должно быть, запутались в именах. Куда должен идти код insert?

Mark Tornej 20.07.2019 13:21

Я предполагаю, что это: myViewModel.insertDatabase(myRoomEntity) - это ваш код вставки. Проверьте ответ еще раз.

Alex 20.07.2019 13:51

Однако, как кажется, вставка ничего не возвращает, вам лучше использовать Completable, а не Observable.

ror 20.07.2019 15:42

@Alex Хорошо, понял, но часть вставки выдает странную ошибку «не существует экземпляра переменной типа T, так что void соответствует T»

Mark Tornej 20.07.2019 16:03

@MarkTornej это потому, что, по-видимому, ваша база данных вставки возвращает пустоту. Вместо этого вы должны использовать Completable.fromAction.

ror 20.07.2019 17:38

@ror Да, мои данные вставки возвращаются недействительными. Но почему/что он должен возвращать? Он только должен вставлять данные, верно?

Mark Tornej 21.07.2019 11:22
Ответ принят как подходящий

Пожалуйста, попробуйте реструктурировать свой код следующим образом:

Completable.fromAction(() -> myViewModel.insertDatabase(myRoomEntity))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(() -> Log.d("TAG", "Populating database Success"),
                        throwable -> Log.d("TAG", throwable.toString()))

Соображения:

  1. Если ваш myRoomEntity недоступен до того, как вся эта конструкция будет подписана, убедитесь, что вы используете deferhttp://reactivex.io/documentation/operators/defer.html
  2. Обработчики вашего раздела подписки работают на «основном», поэтому вы получаете сбой.
  3. По возможности избегайте ненужных just звонков

Потрясающий! Это сработало отлично! Большое спасибо @ror за то, что нашли время :)

Mark Tornej 20.07.2019 22:30

Однако есть одна вещь. Как запустить метод onComplete? Поскольку у меня нет объекта, я не могу получить метод. Я попытался добавить .onComplete в самом конце, но это не сработало...

Mark Tornej 21.07.2019 11:24

О, подождите, добавление .doOnComplete( () -> Log.d("TAG", "COMPLETED" )) перед .subscribe сработало!

Mark Tornej 21.07.2019 11:41

На самом деле, первый обработчик действия в блоке подписки является «завершенным» (для наблюдаемого это будет «следующий»). Но да, ваш подход тоже работает.

ror 21.07.2019 13:51

я использую 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();
                        }
                    });
                }
            });

Другие вопросы по теме