I have simple job which is selecting data using GreenDao. Also i want show ProgressWheel, but this job blocks UI thread.
showLoader();
DataManager.getInstance(this).getQuestions(0, 800)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(QuestionUtils::shuffleAnswers)
.subscribe(this::onFinishLoad);
And
public Observable<List<Question>> getQuestions(int offset, int limit) {
return Observable.fromCallable(() -> daoSession.getQuestionDao().queryBuilder()
.offset(offset)
.limit(limit)
.build().list());
}
It blocks because of the order of your operations.
DataManager.getInstance(this)
.getQuestions(0, 800)
.map(QuestionUtils::shuffleAnswers)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onFinishLoad);
should solve it. Else you would subscribe data and map them after.
If you want to finish the loader onec your data are emitted you can use action in your subscribe method and process the loading in your emitted nextData.
.subscribe (nextData -> {}, error -> {}, () -> doCompletedStuff())
Related
I am trying to download file with RxAndroid and Retrofit, I want my Observable can emit download status on processing.
My expectation:
Observable.create()
.emit(PENDING)
.emit(START)
.flatMap(() -> {
emit(DOWNLOADING);
return apiService.download();
})
.onSuccess(() -> {
emit(SUCCESS);
)
.onError(() -> {
emit(ERROR);
})
You can check the download status with the desired time interval and update the status:
getDownloadStatus()
.zipWith(Observable.interval(500, TimeUnit.MILLISECONDS), (status, interval) -> (String) status)
.repeat()
.distinctUntilChanged()
.doOnNext(status -> ...). //some other operators
Use
Observable.create (emitter -> {})
By emitter.emit(value)
you can do it. But remember free the observable when you've done the task
Hi i am trying to implement a Single observable that chains two requests together.
In between the two requests i make, i notify a callback to update the UI with the response from request one and then launch the next request in the Schedulaers.io thread.
The issue i am having is that it tries to update the UI from the schedulars.io thread too and results to nothing being updated in the ui thread.
i cold wrap the calback on RunOnUiThread code block in android but wondering if there is a more elegant way of doing it?
i checked couroutines and it seems to just deal with putting a block of code in a seperate thread.
Here is my current code
override fun getHomeScreenInformation() {
delegator.requestOne()
.flatMap { responseOne->
homeScreenCallBack.onResponseOneRecieved(responseOne)
delegator.requestTwo()
}
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(
{responseTwo-> homeScreenCallBack.onResponseTwoRecieved(responseTwo)},
{error -> homeScreenCallBack.onError()}
)
}
Apply observeOn(AndroidSchedulers.mainThread()) as many times as necessary:
delegator.requestOne()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) // <----------------------
.flatMap { responseOne ->
homeScreenCallBack.onResponseOneRecieved(responseOne)
delegator.requestTwo()
.subscribeOn(Schedulers.io()) // <----------------------
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{responseTwo-> homeScreenCallBack.onResponseTwoRecieved(responseTwo)},
{error -> homeScreenCallBack.onError()}
)
I'm using the new Android persistance lib, Room, with RxJava2. The following code is causing an infinite loop. If I comment out the line that updates the user in the second observable it works fine. If I leave it there, the onNext method of the first observable will be called on and on again.
Does Room requery the table when an entity is updated? If so, why is it publishing the message again on the same stream? Is this intended behavior? Is it a bug in the library?
val userDao = HeyHeyApp.database.userDao();
userDao.getAll()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ listOfUsers ->
if (!listOfUsers.isEmpty()) {
HeyHeyApp.currentUser = listOfUsers.first()
HeyHeyApp.currentUser.fcmDeviceId = getDeviceId()
Single.fromCallable({
HeyHeyApp.database.userDao()
.updateUser(HeyHeyApp.currentUser)
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ _ ->
})
}
})
When you subscribes for userDao.getAll() event - Room will trigger your observer onNext() method each time when databases data is changed. And next in your onNext() method you change the data in database:
Single.fromCallable({
HeyHeyApp.database.userDao()
.updateUser(HeyHeyApp.currentUser)
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ _ ->
})
and after that Room call your onNext() method again... and so on.
I'm trying to create an Observable such that it will load some data from the network on an interval, and whenever the user refreshes the page. This is the gist of what I have so far:
PublishSubject<Long> refreshSubject = PublishSubject.create();
Observable<MyDataType> observable = Observable.merge(
Observable.interval(0, 3, TimeUnit.SECONDS),
refreshSubject
)
.flatMap(t -> {
// network operations that eventually return a value
// these operations are not observables themselves
// they are fully blocking network operations
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
// update ui with data
}, error -> {
// do something with error
});
Later in a refresh callback I have:
refreshSubject.onNext(0L);
It runs on the interval fine, however when I refresh, it explodes with a NetworkOnMainThreadException. I thought that I handled this with subscribeOn/observeOn. What am I missing? Also, why doesn't this cause a crash when the Observer is triggered from the interval?
You have to change your subscribeOn(Schedulers.io()) to observeOn(Schedulers.io()) and move it over your flatMap.
The reason for this is that your refreshSubject is a PublishSubject, which is an Observable and an Observer.
Since the onNext() of this PublishSubject is called inside the intern Observable first before the result gets delivered to your subscription.
This is also the reason that it works when you just use your Observable(and the fact that interval always subscribes to the computation thread by default).
Just check the output of those two snippets:
Observable.merge(
Observable.interval(0, 3, TimeUnit.SECONDS),
refreshSubject
)
.observeOn(Schedulers.io())
.doOnNext(aLong -> Log.d("Thread", Thread.currentThread().toString()))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
Log.d("Subscribe Thread", Thread.currentThread().toString());
}, error -> {
// do something with error
});
vs
Observable.merge(
Observable.interval(0, 3, TimeUnit.SECONDS),
refreshSubject
)
.doOnNext(aLong -> Log.d("Thread", Thread.currentThread().toString()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(data -> {
Log.d("Subscribe Thread", Thread.currentThread().toString());
}, error -> {
// do something with error
});
I want emit items with a specified delay, repeatedly from an arraylist.
Observable.from(saverFileNameList)
.subscribeOn(AndroidSchedulers.mainThread())
.flatMap(urlString -> Observable.just(urlString)
.delay(5000, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(urlString1 -> {
...
})
).repeat()
.subscribe();
This is not working, for some reason, i have set a print log on onNext, and i can see everything is being printed very fast so the delay is not being applied. What am i doing wrong
If you want to delay the emission of the source by the given amount, you can use the following:
Observable.from(saverFileNameList)
.delay(5000, TimeUnit.MILLISECONDS)
.repeat()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(v -> { }, Throwable::printStackTrace);
If you want to have in-between delay, use the following:
Observable.from(saverFileNameList)
.zipWith(Observable.interval(5, SECONDS).onBackpressureBuffer(), (a, b) -> a)
.repeat()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(v -> { }, Throwable::printStackTrace);