I have the following code which worked perfect in RxJava 1.6.
private PublishSubject<Boolean> mConnectionSubject;
...
Observable.create(subscriber -> {
mConnectionSubject.subscribe(subscriber);
...
});
But after migration to RxJava 2.0 this code doesn't compile. The reason is that Observable.create() now accepts as argument ObservableEmitter. But PublishSubject doesn't accept ObservableEmitter. It accepts only Consumer or Observer interface.
Will appreciate any suggestions.
I would do something like below in the scenario you have mentioned.
Observable.<Boolean>create(emitter -> mConnectionSubject.subscribe(
emitter::onNext,
emitter::onError,
emitter::onComplete
));
You don't need to create a new observable, this should work:
private PublishSubject<Boolean> mConnectionSubject;
...
mConnectionSubject.doOnNext(...).observeOn(...).subscribe();
You can chain multiple operators/subscriptions to the PublishSubject.
Related
I want to use coroutine in my kotlin app for must of it. but this app depends a lot on a service which return rxjava2 type object (so our input will be all the rxjava type). How can we still use coroutine in this model app instead of rxjava2. should we create a layer only convert rxjava object to normal object (or coroutine object?). or can we use both two together like:
SomeObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value->
viewmodelScope.launch{
// send a flow or coroutine suspend fonction with value
}
},
Thanks,
You could wrap the RxJava functions with suspend functions.
See https://github.com/Kotlin/kotlinx.coroutines/issues/869
I want to answer my own question, It's not a good approche to use flow and rx at the same time. because it resolves the same problem. Rxjava + livedata is a clean architecture to go. or just use flow. so for resume:
Rxjava + livedata (a little bit coroutine to do some general
operation)
flow + coroutine
Two clean ways to make a good architecture. so if I have already rx type there is no need to convert to flow and reuse.
In Rxjava1 we can subscribe Subject to an Observable like this:
val asyncSubject = AsyncSubject<T>.create()
Observable<T>.subscribe(asyncSubject);
asyncSubject.subscribe(...)
Can't figure out how to achieve the same thing in Rxjava2 Flowable?
I'm thinking about something like this
Flowable<T>
.doOnComplete { t -> asyncSubject.OnComplete() }
.subscribe { t -> asyncSubject.onNext(t) }
Is there better/more concise way?
RxJava2 Separated things out into Flowable and Observable. Flowables are used when you want back-pressure.
Due to this break-out, we have two different types of Subject objects, your regular old BehaviorSubject, etc. which work with Observable, and a new set of classes called Processors, such as BehaviorProcessor, etc.
These classes work in mostly the same way as subjects, but are utilizable with Flowables instead of Observables.
In your case, you would want to use a Processor instead of a subject:
val proc = AsyncProcessor.create<Int>()
val flowable = Flowable.just(1)
flowable.subscribe(proc)
I am new to Kotlin, coming from C# it I am quite used to async\await
How do I wait for tvClient to get the response before returning the list of channels?
override fun getChannels(): MutableList<Channel> {
disposable = tvClient.getChannels()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{Log.d("***", it.toString())},
{Log.d("***",it.toString())}
)
TODO("wait for tvClient to return results")
return mChannels;
}
I tried using coroutines but no luck
What is the best way to wait for async operation to complete in Kotlin?
You're using RxJava and thus you should implement it in a reactive way.
If you're app is not build for it yet, you can get the value blocking. Assuming getChannels() returns a single you could just call blockingGet() instead of subscribe().
But be aware that this blocks the thread the outer getChannels() is called from.
Using coroutines might be better for you. It's a little nearer to what you know from C# and with the retrofit2-kotlin-coroutines-adapter you can integrate directly with Retrofit.
You could look into using the retrofit coroutine adapters from Jake Wharton https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter
you can check a functional implementation of kotlin v1.3 retrofit + stable coroutines using DSL here https://github.com/eriknyk/networkcall-sample/commits/master
DSL template:
fun <RESPONSE: DataResponse<*>, DATA: Any> networkCall(block: CallHandler<RESPONSE, DATA>.() -> Unit): MutableLiveData<Resource<DATA>>
= CallHandler<RESPONSE, DATA>().apply(block).makeCall()
interface DataResponse<T> {
fun retrieveData(): T
}
and using it:
fun getRepos(query: String) = networkCall<ResposResponse, List<Repo>> {
client = githubService.getRepos(query)
}
Hope it helps.
Why is my compiler not allowing myself to subscribe on an Observable with a TestSubscriber?
Here's my code:
TestSubscriber<User> testSubscriber = new TestSubscriber<>();
Observable.just(new User()).subscribe(testSubscriber);
And it's saying that it can't resolve method subscribe which is taking this parameter. But in all RxJava testing tutorials, they are using TestSubscriber without such problems. What can I do to test such Observable?
It is because *Subscriber are meant for Flowable while Observable uses the *Observer classes. This is because the reactive-streams standard reserves Subscriber for the fully compliant Publisher interface which Flowable implements.
Additionally with RxJava2 all reactive classes have a .test() method which will directly give you the appropriate testing object.
For RxJava 1 → RxJava 2 migration, I've just replaced TestSubscriber with TestObserver to make Observable#subscribe call compile and work.
You can change Observable to Flowable if you want to test with TestSubscriber as follow:
TestSubscriber<User> testSubscriber = new TestSubscriber<>();
Flowable.just(new User()).subscribe(testSubscriber);
I am wondering how to test Retrofit2 call via rxjava2. My retrofit api interface looks like:
public interface LoginApiMapping {
#POST("v1/secm/oam/oauth2/token")
Observable<Response<RestResponseHolder<LoginResponseModel>>> login(#Body LoginModel model);
}
and i would like to write the test which will send this request via RxJava2 and check the response. I consider that there is the problem with RxJava as it is asynchronous and the test finishes before i get the response, so i tried to use TestSubscriber as below, but it's not possible to subscribe TestSubscriber<Response<RestResponseHolder<LoginResponseModel>>> as i expected
#Test
public void loginTest(){
Context appContext = InstrumentationRegistry.getTargetContext();
Api t = TestApi.create(appContext);
LoginModel loginModel = new LoginModel("username","password");
TestSubscriber<Response<RestResponseHolder<LoginResponseModel>>> testSubscriber = new TestSubscriber<>();
t.get(LoginApiMapping.class).login(loginModel).subscribe(testSubscriber);
}
anyone who solved that? thanks
I finally found the solution, so i decided to post it here.
First you have to call toFlowable() on the observable and set the Backpressure strategy and then you can subscribe with TestSubscriber as below
t.get(LoginApiMapping.class).login(loginModel).toFlowable(BackpressureStrategy.DROP).subscribe(testSubscriber);
Then add
testSubscriber.awaitTerminalEvent();
at the end that you can check various assertions on testSubscriber as R. Zagórski pointed in answer above.
At the end of of test add:
testSubscriber.awaitTerminalEvent();
Then you can check various assertions on testSubscriber.
You use TestSubscriber with Flowable and TestObserver with Observable. You can test Single, Completable and Maybe by converting them to either Flowable or Observable, but the built-in test()s for these three return TestSubscriber.