RxJava2 - Merge values and side effects from a stream - java

I'm trying to extract some common logic, based on RxJava2, into reusable components. Let's imagine I have the following piece of code:
someSingle
.doOnSuccess { // update UI based on side effect }
.subscribeOn(...)
.observeOn(...)
.subscribe(
value -> // update UI based on value
throwable -> // handle error
)
I want to wrap this into a reusable component, exposing a method that returns a Flowable of events. The clients will receive events and update the UI accordingly. My goal is not to have any reference of the view inside the reusable component. I want the method to be something like this:
fun reusableMethod(...) : Flowable<Event> { ... }
Event is a sealed class, enclosing two sub types - SideEffectEvent and ValueEvent.
What is the best way to transform the stream from the first snippet, so I can get both the side effect and the value to be emitted as flowable values?
Currently, I have the following solution, but I'm not very happy with it, because it looks a bit clunky and complex:
private val sideEffectEvents = PublishProcessor.create<SideEffectEvent>()
fun reusableMethod(...) =
Flowable.merge(
someSingle.doOnSuccess { sideEffectEvents.onNext(SideEffectEvent()) },
sideEffectEvents
)
.subscribeOn(...)
.observeOn(...)
I have also considered some alternatives:
Notify the client for SideEffectEvents using a callback that is passed to someReusableMethod() - looks very unnatural and having a callback and a stream to subscribe to is not a good code style
Use a single PublishProcessor. Post side effects to it and use it to subscribe to the original Single. Expose a cleanUp() method in the reusable component so the client can dispose of the stream when it decides to.
I'm looking forward to suggestions and ideas.

First of all it doesn't have to be a Flowable. It can be a simple Observable. But the below solution should work in both cases. read more here Observable vs Flowable
This code is not tested, I have written it to give you a simplified idea about how you can achieve this.
// a sealed class representing current state
sealed class ViewState {
object Loading : ViewState() // using object because we do not need any data in cass of loading
data class Success(val data: List<Model>) : ViewState()
data class Error(val t: Throwable) : ViewState()
}
// an observalbe or flowable returning a single object ViewState
// it will always return ViewState class containing either data or error or loading state
return service.getData()
.map { data -> ViewState.Success(data) } // on successful data fetch
.startWith(ViewState.Loading()) // show loading on start of fetch
.onErrorReturn { exception -> ViewState.Error(exception) } // return error state
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
// somewhere in Activity or in multiple activities subscribe to above observable
subscribe({ viewState ->
when {
viewState.Loading -> showProgressView()
viewState.Error -> showErrorView(viewState.t)
viewState.Success -> showData(viewState.data)
else -> IllegalArgumentException("Invalid Response")
}
})

How about this:
Before:
someSingle
.operation1()
.operation2()
.doOnSuccess { // update UI based on side effect }
.operation3()
.operation4()
.subscribeOn(...)
.observeOn(...)
.subscribe(
value -> // update UI based on value
throwable -> // handle error
)
Reusable:
fun reusableMethod(...): Flowable<Event> =
someSingle
.operation1()
.operation2()
.flatMapPublisher {
Single.concat(
Single.just(getSideEffectEvent(it)),
Single.just(it)
.operation3()
.operation4()
.map { value -> getValueEvent(value) }
)
}
.subscribeOn(...)
.observeOn(...)
You can further simplify this using Flowable#startWith, and avoiding Single#concat()

Related

How to error handle for 20 reactive async API calls in java?

I'm writing a service that calls 20 external vendor APIs, aggregates that data and writes it to a blob storage. This is how I am calling each api, after I am using Mono.zip() and writing that result into a blob storage. However I feel that the way I am writing the code is really redundant, specifically the error handling using .onErrorResume() and .doOnSuccess() Is there a way I can maek this code cleaner by using generics or utilizing inheritance some way? I just dont want hundreds of lines of code that are basically doing the same thing...
Mono<MailboxProvidersDTO> mailboxProvidersDTOMono = partnerAsyncService.asyncCallPartnerApi(getMailboxProvidersUrl, MailboxProvidersDTO.class)
.retryWhen(getRetrySpec())
//need to have error handling for all 20 api calls
.doOnSuccess(res -> {
log.info(Logger.EVENT_SUCCESS, "Mailbox Providers report successfully retrieved.");
res.setStatus("Success");
})
.onErrorResume(BusinessException.class, ex -> {
log.error(Logger.EVENT_FAILURE, ex.getMessage());
MailboxProvidersDTO audienceExplorerDTO = new MailboxProvidersDTO();
audienceExplorerDTO.setStatus("Failed");
return Mono.just(audienceExplorerDTO);
});
Mono<TimeZonesDTO> timeZonesDTOMono = partnerAsyncService.asyncCallPartnerApi(getTimeZonesUrl, TimeZonesDTO.class);
Mono<RegionsDTO> regionsDTOMono = partnerAsyncService.asyncCallPartnerApi(getRegionsUrl, RegionsDTO.class);
Mono<AudienceExplorerDataSourcesDTO> audienceExplorerDataSourcesDTOMono = partnerAsyncService.asyncCallPartnerApi(getAudienceExplorerDataSourcesUrl, AudienceExplorerDataSourcesDTO.class);
...
You can effectively use generics to refactor your code. You can couple functional interfaces and Generics to create what you need:
On your example, you need both to "setStatus" and create new instances of different classes. You could then create a utility function to add onSuccess/onFailure behaviours over your initial data fetching Mono:
public <T> Mono<T> withRecovery(Mono<T> fetchData, BiConsumer<T, String> setStatus, Supplier<T> createFallbackDto) {
return fetchData
.doOnSuccess(result -> {
log.info...
setStatus.accept(result, "Success");
})
.doOnError(BusinessException.class, err -> {
log.error...
T fallback = createFallbackDto.get();
setStatus.accept(fallback, "Error");
return Mono.just(fallback);
});
}
Then, you can use this method like that:
Mono<MailProvidersDto> mails = withRecovery(
partnersAsyncService.asyncCallPartnerApi(getMailboxProvidersUrl, MailboxProvidersDTO.class),
MailProvidersDto::setStatus,
MailProvidersDto::new
);
Mono<TimeZoneDto> timezone = withRecoery(
partnersAsyncService.asyncCallPartnerApi(getMailboxProvidersUrl, TimeZoneDto.class),
TimeZoneDto::setStatus,
TimeZoneDto::new
);
... // Repeat for each api
Notes:
If the setStatus method is available through a common interface that all DTO implement, you can get rid of the biconsumer, and directly call result.setStatus(String), by specializing T generic to T extends StatusInterface.
With it, you could also factorize initial fetching and retry calls, by passing related parameters (url, class, retry spec) as method input.

RxJava, Room: Best way to update all the rows of Db using rxjava chain calls

I'm using rxjava & Room where I'm trying to update list of rows in db.
Stuck in a loop where events are continuously firing
Dao
#Query("SELECT * FROM movies")
Flowable<List<Movie>> getMovies();
#Update
int updateMovie(Movie movie);
UpdateClass - helper classes is updating the Db like this
// Trying to get all existing movies and update one value in all of them.
#WorkerThread
Flowable<Integer> updateMovies(Helper help) {
return movieDao.getMovies().flatMapIterable(movies -> movies)
.flatMap(movie -> {
LogUtils.debug("movieusecase", "movieid" + movie.getMovieId());
movie.updateRating(help.getUpdatedVal(movie));
return Flowable.just(movie);
}).map(movie -> {
return movieDao.updateMovie(movie);
});
}
As soon as I include the updateMovie call I get stuck in an infinite loop where duplicate events keep on coming from room db.
Presenter Class - calls update class to update stuff in db. Gets triggered in activity onCreate
updateClass.updateMovies()
.observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(movie -> {
// update stuff
}, throwable -> {
LogUtils.error(TAG, throwable.getMessage());
});
Thanks in advance any help would be really appreciated.
Sounds like a job for a Single instead of a Flowable.
The difference is that Single will only fire once with the current list of movies in the DB, It will not keep emitting changes like Flowable does.
Single<List<Movie>> getMovies();
Or if you for some reason want your method to return Flowable, You can also use Flowable.firstOrError() which will transform your Flowable into a Single with a cost.
#WorkerThread
Flowable<Integer> updateMovies(Helper help) {
return movieDao.getMovies()
.firstOrError()
.flatMapIterable(movies -> movies)
.flatMap(movie -> { ... })
.map(movie -> { ... });
}
I prefer the first option though for the sake of intention clarity.

how to convert asynchronous promise code to rxjava

I have the following synchronous code that I would like to model as async code in RXJava.
void executeActions(List<Action> action) {
if (action == null || action.size() == 0) return;
for (Action action: actions) {
executeActions(action.handle());
}
}
class Action {
//implementation of handle
// return List<Action> or null.
List<Action> handle() {
}
}
Now in JS I can model this interaction with Promises like so. (Pseudo code below - my JS is weak)
executeActionsAsync(actions) {
var p = Promise.resolve();
action.forEach(function(action) {
p = p.then(function() {
action.handle();
})
}
return p;
}
class Action() {
function handle() {
actions = [];// some array of actions.
executeAsync(actions);
}
}
I would like to model the same in RXJava2. Any help is appreciated.
First of all, Sorry for my bad English.
I edited entire answer because I did not catch what his question is.
I don't know how implement of your Action class's handle function, However this function return value should change to RxJava2's async classes. In this case, Maybe class.
You wants how to implements recursion of async.
Handle List or null.
Use Maybe if you want to handle something or null. in RxJava2
class Action {
Maybe<List<Action>> handle() {}
}
This is what your Action class's handle returns.
void executeActions(Maybe<List<Action>> rxactions) {
// add null check.
// List<Action> handles as stream, but you can use for or iterator or whatever you want.
rxactions.subscribe(actions -> actions.stream().map(action -> executeActions(action.handle())));
}
Important thing is, handle() function returns properly.
Additional
In RxJava2, There are multiple classes to handle async.
Single, Flowable, Observable, Completable. And each classes instance method, subscribe.
Simply say,
1.Single => returns single class.
2.Flowable, Observable => returns multiple classes. (Flowable is more complex than Observable, which added back pressure.)
3.Completable => returns nothing, just succeed or not.
4.Maybe is returns * or null.
5.subscribe is execute this async.
:: Each classes can convert easily.
:: And There are so many ways to solve one problem. so it is just reference.
ex) Single<List<Foo>> <=> Flowable<Foo> // This is not same. but treat as similar.
PS.
I had this experience too. I think you need to learn more about RxJava2 to use properly everywhere.
Promise can devide into Single, Flowable, Observable, Completable. As describe above. This is the KEY to start understanding RxJava2.

Callback with parameters with Kotlin

I just started Kotlin so please be nice :)
I have a class that is responsible for fetching some data and notify the main activity that its need to update its UI.
So i have made a function in my DataProvider.kt :
fun getPeople(fromNetwork: Boolean, results: ((persons: Array<Person>, error: MyError?) -> Unit)) {
// do some stuff stuff
val map = hashMapOf(
"John" to "Doe",
"Jane" to "Smith"
)
var p = Person(map)
val persons: Array <Person> = arrayOf (p)
results(persons, null)
}
So i want to call this from my activity but i can't find the right syntax ! :
DataProvider.getPeople(
true,
results =
)
I have try many things but i just want to get my array of persons and my optional error so i can update the UI.
The goal is to perform async code in my data provider so my activity can wait for it.
Any ideas ? Thank you very much for any help.
This really depends on how you define the callback method. If you use a standalone function, use the :: operator. First (of course), I should explain the syntax:
(//these parenthesis are technically not necessary
(persons: Array<Person>, error: MyError?)//defines input arguments: an Array of Person and a nullable MyError
-> Unit//defines the return type: Unit is the equivalent of void in Java (meaning no return type)
)
So the method is defined as:
fun callback(persons: Array<CustomObject>, error: Exception?){
//Do whatever
}
And you call it like:
DataProvider.getPeople(
true,
results = this::callback
)
However, if you use anonymous callback functions, it's slightly different. This uses lambda as well:
getPeople(true, results={/*bracket defines a function. `persons, error` are the input arguments*/persons, error -> {
//do whatever
}})
Yes Kotlin has a great way of using callback functions which I will show you an example of how I use them below:
fun addMessageToDatabase(message: String, fromId: String, toId: String,
addedMessageSuccessHandler: () -> Unit,
addedMessageFailureHandler: () -> Unit) {
val latestMessageRef = mDatabase.getReference("/latest-messages/$fromId/$toId")
latestMessageRef.setValue(message).addOnSuccessListener {
latestMessageUpdateSuccessHandler.invoke()
}.addOnFailureListener {
latestMessageUpdateFailureHandler.invoke()
}
}
And finally you can utilise the new callbacks with the following code
databaseManager.updateLatestMessageForUsers(message, fromId, toId,
latestMessageUpdateSuccessHandler = {
// your success action
},
latestMessageUpdateFailureHandler = {
// your failure action
})
So basically when I successfully add a new row to my database I'm invoking a success or a failure response to the caller of the service. Hopefully this will help out someone.

Filter RxJava Observable with other Observable

I'm using RxAndroid 2.0.1 with RxJava 2.0.6.
I have two observables: one returns Maybe<MyObject> based on some String (ID). When the optional object is returned, I have to call the second one that takes the MyObject instance and returns Single<Boolean> if object meets some conditions. Then I can do some further operations with the object instance.
My current implementation is as follows:
objectDAO.getById(objectId)
.subscribe(
myObject -> checkCondition(myObject),
throwable -> /* Fallback */,
() -> /* Fallback */
);
private void checkCondition(final MyObject myObject) {
otherDAO.checkCondition(myObject)
.subscribe(
isTrue -> {
if (isTrue) {
// yay! now I can do what I need with myObject instance
} else {
/* Fallback */
}
},
throwable -> /* Fallback */
);
}
Now I'm wondering how could I simplify my code. My ideas:
Try to use zip - I can't because second Observable can't be subscribed until the first one returns the MyObject
Try to use filter - Now the issue is that I need to use blocking get to call second observable. It will propably work, but looks like a code smell:
objectDAO.getById(objectId)
.filter(myObject ->
otherDAO.checkCondition(myObject).blockingGet()
)
.subscribe(
myObject -> checkCondition(myObject),
throwable -> /* Fallback */,
() -> /* Fallback */
);
Try to use flatMap - The second observable returns Boolean while I need to return the original object. Because of that I need to mape a code snippet with blockingGet and return original object or Maybe.empty()
Any suggestions how to do it in such a way that the code is "clean" (it's smaller and it's still clear what's happening inside)?
One thing you could do:
objectDAO.getById(objectId)
.flatMapSingle(myObject -> otherDAO
.checkCondition(myObject)
.map(isTrue -> Pair.create(myObject, isTrue))
)
Then you have an Observable<Pair<MyObject, Boolean>> and can proceed however you want: subscribe directly and check the Boolean there, filter by the Boolean value, etc.
The RxJava2Extensions extra project by akarnokd has a filterAsync transformer (to be used with compose) that does just that, using a any Publisher<Boolean> ;)
I've come up with solution without passing Pairs with boolean values, in case anybody will face same problem.
For example, if objectDAO.getById(objectId) returns Observable<T> and otherDAO.checkCondition(myObject) returns Single<Boolean>, we can handle filtering in such a way:
objectDAO.getById(objectId)
.flatMap(myObject -> otherDAO
.checkCondition(myObject)
.toObservable()
.filter(Boolean::booleanValue)
.map(o -> myObject))
.flatMapSingle(obj -> ...)
Unwanted objects will be resolved to Observable.empty and thus filtered, so that only needed objects will get to .flatMapSingle(obj -> ...)
Basically, same thing can be achieved with slightly easier to understand structure (though, I've found the first one a bit nicer aesthetically):
objectDAO.getById(objectId)
.flatMap(myObject -> otherDAO
.checkCondition(myObject)
.flatMapObservable(isChecked -> isChecked ? Observable.just(myObject) : Observable.empty()))
.flatMapSingle(obj -> ...)

Categories

Resources