theanilpaudel
theanilpaudel

Reputation: 3488

RxJava not running on Background thread

I am trying to save data in Room and it requires some background thread to save data. So I have created an observable like this

val obs: Observable<MutableLiveData<List<Source>>>? = Observable.fromCallable(object :Callable<MutableLiveData<List<Source>>>{
            override fun call(): MutableLiveData<List<Source>> {

                return mutableLiveData
            }
        })

Then I am subscribing, observing and unsubscribing it like this

obs?.subscribeOn(Schedulers.io())?.observeOn(AndroidSchedulers.mainThread())?.unsubscribeOn(Schedulers.io())
                ?.subscribe(object : Observer<MutableLiveData<List<Source>>>{
                    override fun onComplete() {

                    }

                    override fun onSubscribe(d: Disposable?) {

                    }

                    override fun onNext(value: MutableLiveData<List<Source>>?) {
                        for(source in value!!.value!!.iterator()){
                            sourceDao.insert(source)//this is the line number 87, that logcat is pointing
                        }
                    }

                    override fun onError(e: Throwable?) {
                        e?.printStackTrace()
                    }
                })

I am subscribing it on the Schedulers.io thread then observing it on the AndroidSchedulers.mainThread() but still I am getting not on background thread error. More specifically

    Caused by: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        at android.arch.persistence.room.RoomDatabase.assertNotMainThread(RoomDatabase.java:204)
        at android.arch.persistence.room.RoomDatabase.beginTransaction(RoomDatabase.java:251)
06-18 11:11:08.674 3732-3732/com.theanilpaudel.technewspro W/System.err:     at com.package.myapp.room.SourceDao_Impl.insert(SourceDao_Impl.java:63)
        at com.package.myapp.main.MainRepository$saveToRoom$1.onNext(MainRepository.kt:87)
        at com.package.myapp.main.MainRepository$saveToRoom$1.onNext(MainRepository.kt:76)

Upvotes: 1

Views: 1628

Answers (2)

Adib Faramarzi
Adib Faramarzi

Reputation: 4060

It makes sense because you have observeOn the main thread and you are doing your work in the observer (observeOn manages the thread of the observer).

To fix this, you can use flatmap on your obs and do the for loop in there. Since flatmap requires you to return an Observable, you can return Observable.just(true) after your for loop.

Upvotes: 1

Christopher
Christopher

Reputation: 10279

Execute your DB operation within the Observable and not in your Observer:

val obs: Observable<MutableLiveData<List<Source>>>? = Observable.fromCallable(object :Callable<MutableLiveData<List<Source>>>{
        override fun call(): MutableLiveData<List<Source>> {
             for(source in mutableLiveData!!.value!!.iterator()){
                  sourceDao.insert(source)
             }
            return mutableLiveData
        })
        .subscribeOn(Schedulers.io())?.observeOn(AndroidSchedulers.mainThread())?.unsubscribeOn(Schedulers.io())
            ?.subscribe(object : Observer<MutableLiveData<List<Source>>>{
                override fun onComplete() {

                }

                override fun onSubscribe(d: Disposable?) {

                }

                override fun onNext(value: MutableLiveData<List<Source>>?) {
                    // Nothing todo right more
                }

                override fun onError(e: Throwable?) {
                    e?.printStackTrace()
                }
            })
    })

Upvotes: 2

Related Questions