如何用RxJava Observer代替Asynctask?

时间:2019-07-20 10:06:55

标签: android-studio asynchronous rx-java android-room

我有一个带有Room数据库的测试项目。使用Asynctask,可以成功地将包含一些测试数据的对象插入数据库。我正在尝试学习RxJava,并将Asynctask替换为RxJava's observer,但这是行不通的。我已经阅读了许多文档并观看了教程,但我认为我不太明白。以下是相关代码:

在这里,将Room中的数据设置为List对象:

for(ObjectForArray item: listToDatabase) {
        myRoomEntity.setName( item.getName() );
        Log.d( "TAG", myRoomEntity.getName() );
    }

然后,我尝试使用RxJava Observable将数据插入数据库。最初是使用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() );
            }
        }

OnNextOnErrorOnComplete为空。

当我运行项目时,它崩溃并显示错误:

Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

我显然使用RxJava是错误的,因为重点是要在远离主线程的地方执行异步任务。

3 个答案:

答案 0 :(得分:1)

由于尝试在主(UI)线程上插入对象而收到此错误。

您应该执行以下操作:

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

然后使用观察者来订阅Observable。

答案 1 :(得分:0)

请尝试像这样重组代码:

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不可用,请确保使用defer http://reactivex.io/documentation/operators/defer.html
  2. 您的订阅部分处理程序正在“ main”上运行,这就是您收到崩溃的原因。
  3. 如果可能,避免不必要的just通话

答案 2 :(得分:0)

我已使用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了,我将让您知道可以在哪里放置后台任务,执行前,执行后异步任务

首先让我们开始使用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();
                        }
                    });
                }
            });