Let's say your DAO has this method that updates user records in the DB:
#Update
fun update(user: User): Single<Int>
Recently I started learning RxJava and so far I have seen lots examples like following:
// Example 1
disposable.add(dao.updateUser(user)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
Log.d(TAG, "response received")
}
In the above example, I understand that as soon as the subscription starts, updateUser() will be executed on a worker thread and the subscriber will be notified and run in the main thread once the execution completes.
But what if you are not interested in the result of updateUser(), and all you want is just to execute updateUser() on a worker thread?
So far I have tried doing:
// Example 2
dao.updateUser(user)
or
// Example 3
dao.updateUser(user).subscribeOn(Schedulers.io())
But they didn't work. It seems the update requests are never executed, nothing was logged and records didn't change. I am guessing that's because there isn't any subscriber attached to it.
For now I am forcing it to work by attaching a random subscriber that doesn't really do anything like the one in Example 1. One of the problems with the approach is that I might need to make this request a lot and that might create a lot of dummy subscribers, not to mention that the code looks really bad.
Could you help me find a better way of handling this?
But You already wrote answer for Your question.
You can just call:
dao.updateUser(user).subscribe()
If You want manipulate / jump between thread you are doing something like in Example 1.
Related
I'm trying for some time now to implement an extension function (just becuse it's easier to me) that is capable of delaying both normal item emissions and errors. The existing delay operators only delays normal item emissions, errors are delivered ASAP.
For context, I'm trying to immitate an Android LiveData's behavior (kinda). LiveDatas are a observable pattern implementation that is lifecycle aware. Their observers are only notified if they are in a state where they can process that emission. If they are not ready, the emission is cached in the livedata and delivered as soon as they become ready.
I created a BehaviourSubject that emits the state of my Activities and Fragments when it changes. With that I created a delay operator like this:
fun <T> Flowable<T>.delayUntilActive(): Flowable<T> = delay { lifecycleSubject.toFlowable(BackpressureStrategy.LATEST).filter { it.isActive } }
and then use it like this
myUseCase.getFlowable(Unit)
.map { it.map { it.toDisplayModel() } }
.delayUntilActive()
.subscribe({
view.displaySomethings(
}, { }).addTo(disposables)
So even if myUseCase emits when the view is not ready to display somethings, the emission won't reach onNext() until the view does become ready. The problem is that I also want the view to displayError() when onError is triggered, but that too is lifecycle sensitive. If the view isn't ready, the app will crash.
So I'm looking for a way to delay both emissions and errors (onComplete would be good too). Is this possible?
I tried some things with zip, onErrorReturn, delay inside delay, but nothing seemed right. I'd be equally unimpressed if this had a really easy solution I'm overlooking, or is impossible. Any ideas are welcome.
Bonus: any better way to do that for Single and Completable too? currently I'm just converting them to flowable.
Thanks in advance!
You can handle the error via onErrorResumeNext, then taking the same error and delaying it via delaySubscription until your desired signal to emit said error happens:
source
.onErrorResumeNext({ error ->
Observable.error(error)
.delaySubscription(lifecycleSubject.filter { it.Active } )
})
I am relatively new to reactive world , In My codebase I have decided to apply reactive philosophy in a very incremental way which is taking small step at a time . whit this motivation I have a changed a function this way
public List<Task> getFilteredTask() {
return Observable.fromIterable(TaskDataSource.getAllTasks())
.filter(task -> !task.isCompleted && !task.getPriority>=1)
.sorted((task!, task2) -> task.title.compareTo(task2.tilte)).toList().blockingFirst();
I Had to useBlockingX() operator my client recieves List for this time being . So I had to unwrap the Single Observable .
But I am getting exception after calling this ? Please Help me What am I doing wrong here ?
Please post your Log messages , although I am pretty much sure You are getting this error as you possibly calling this method from MainThread . As You know long running operation supposed to be deferred off to Main Thread .
Second Thing I would Like to address is RxJava was created with Laziness in mind . Here you are violating it with Observable Creation with Observable.fromIterable(TaskDataSource.getAllTasks()) as You can see TaskDataSource.getAllTasks() is getting called even before there is any observer subscribed to it . So I think with this modification you will get rid of the crash
public Observable<Task> getFilteredTask() {
return Observable.defer(() ->
Observable.fromIterable(TaskDataSource.getAllTasks())).subscribeOn(Schedulers.io())
.filter(task -> !task.isCompleted && !task.getPriority>=1)
.sorted((task!, task2) -> task.title.compareTo(task2.tilte))
.observeOn(AndroidSchedulers.mainThread());
}
Further more I would like to say modify you'r calling client for accepting Observable instead of List . Because Using BlockinX() is strongly discouraged by Rx Community because Instead of Being data Pushed as It is ready you are pulling data and blocking the thread
Hope it will help
I want to make API calls using Retrofit2 library, returns generic type observable.
I am getting an error: android.os.NetworkOnMainThreadException, while making calls.
Looks really easy to solve, two cases to consider. :1)If you are not using RXJava or 2) if you are using it
1) If you are NOT using RXJava
You should use the method enqueue when you make the call. The error you get is because you are calling the response on the same Thread(the MainThread)
Here is an example took from the web that uses Enqueue with Kotlin that possibly you can adapt to your case
override fun loadPokemonList(pokemonListListener: PokemonListListener) {
call = pokemonService.getPokedex();
call.enqueue(object : Callback<PokeDex> {
override fun onResponse(call: Call<PokeDex>?, response: Response<PokeDex>?) {
if (response != null && response.isSuccessful) {
pokemonListListener.onSuccess(response.body())
} else {
pokemonListListener.onFailure(appContext.getString(R.string.error_fetching_data))
}
}
override fun onFailure(call: Call<PokeDex>?, t: Throwable?) {
pokemonListListener.onFailure(appContext.getString(R.string.error_fetching_data))
}
})
}
2) If you are using RXJava(usually version 2, be aware you will find several tutorials for the first version online)
But please consider that most of the developers today solve this asynchronous call using RXJava2 that is the second case I was mentioning at the beginning of he post. It will take you several hours to understand the basics of it but once you will do, you will have a great skill to bring with you and manage this kind of calls( even multiple ones) will be really simple. In fact RXJava allows you really easy to direct the operation in a concurrent Thread and observe the result on the Main Thread. Here a good tutorial that explains how to do that
with the easy and well known pattern (see the notations)
Observable<List<TrendsResponse>>
.subscribeOn(Schedulers.io())//Run the call on another Thread
.observeOn(AndroidSchedulers.mainThread())//observe on the Main Thread
.subscribe();
Differently by what people new to RXJava think:
on default RXJava does not call a concurrent Thread, is up to you to do that with the subcribeOn that does all the "dirty" work and then to observe the result on the Main Thread with ObserveOn.
For principiants is easy to grasp that comparing both of them to the two famous methods of AsyncTask: doInBackground and onPostExecute
EDIT: Please look also this post if you or future users have problems.
With Retrofit/RxJava, the network call will be default be performed on the thread that subscribes to the Observable returned from the stub. On Android, we are normally executing on the "main" thread, and it is not permitted to access the network on this thread, hence the error.
The solution is to tell RxJava to subscribe to the Observable on a different thread:
getDataFromAPI(/*...*/)
.subscribeOn(Schedulers.io())
.observerOn(AndroidSchedulers.mainThread())
.subscribe({ /* result available in `it` */ })
Schedulers.io() is a reference to a scheduler that uses a set of threads specifically intended to be used for IO operations.
The .observeOn allows you to handle the result safely back on the main thread.
I'm feeling a bit curious about how .subscribeOn() actually works on RxJava.
I have this piece of code that works as intended:
return endpoints.getRecentConversations(page)
.map().flatMap().doOnNext() //etc etc...
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
I was reading this article, trying to understand what the difference between subscribeOn and observeOn when this line caught my eye:
Position does not matter
subscribeOn can be put in any place in the stream because it affects
only the time of subscription
Which sounds perfectly fine. But I was feeling a bit skeptical I decided to test it. So I changed the code above (switched lines 2 and 3):
return endpoints.getRecentConversations(page)
.subscribeOn(Schedulers.io())
.map().flatMap().doOnNext() //etc etc...
.observeOn(AndroidSchedulers.mainThread())
As a result, I get an premature onComplete() on my subscriber. onNext() is never called and no errors are present in my logcat.
I can leave things the way they were, but I'd like to know why this is happening. Is it true that position doesn't matter? Is it something wrong with my code? Here's how my code looks
Yes, the position does matter a lot in RxJava, It's called upstream & downstream.
It's because you are subscribing to a hot observable
Watch this video to understand it better: Common RxJava Mistakes
https://www.youtube.com/watch?v=QdmkXL7XikQ&t=768s
There are two types of observables: Hot & cold.
A “hot” Observable may begin emitting items as soon as it is created,
and so any observer who later subscribes to that Observable may start
observing the sequence somewhere in the middle. A “cold” Observable,
on the other hand waits until an observer subscribes to it before it
begins to emit items, and so such an observer is guaranteed to see the
whole sequence from the beginning.
As i understand AndroidObservable helps ensure that :
a Subscriber always observes on the main thread
when a fragment/activity is detached/stopped, then the observation stops immediately, and framework related components (like ui textviews etc.) are not updated.
However, in order to ensure that the context is released (preventing leakage), most examples I see typically say that you have to anyway do an .unsubscribe onDestroyView/onDestroy, which essentially halts the subscription, and prevents the subscriber from receiving these updates anyway.
So my question is:
Is there any other advantage to using AndroidObservables, if i manually indicate that the subscription should happen on the main thread, by way of .observeOn(AndroidSchedulers.mainThread() ?
Is there any difference in the below two approaches?
_subscription1 = AndroidObservable.bindFragment(MyFragment.this, myCustomAwesomeObservable()) //
.subscribeOn(Schedulers.io()) //
.subscribe(...);
_subscription2 = myCustomAwesomeObservable()
.subscribeOn(Schedulers.io()) //
.observeOn(AndroidSchedulers.mainThread()) //
.subscribe(...);
#Override
public void onDestroyView() {
_subscription1.unsubscribe();
_subscription2.unsubscribe();
super.onDestroyView();
}
You are right. What AndroidObservable.bindFragment currently does is:
This helper will schedule the given sequence to be observed on the main UI thread and ensure that no notifications will be forwarded to the activity in case it is scheduled to finish.
-- part of the source code comment
So, it does not really make a difference which of the implementations you use.
But, still it's a good idea to use the AndroidObservable as additional functionality could be added in the future.
It doesn't exist anymore since 1.0 release of RxAndroid. I guess you could say it's deprecated or discontinued. I don't think it's a good idea to use this anymore.