Reputation: 421
I'm developing an Android app using Clean Architecture and I'm migrating it to RxJava 2.x. I have to make some network requests to a soap service, so I defined the api interface in the domain module:
public interface SiginterApi {
Observable<User> login(String user, String password);
...
Observable<List<Campaign>> getCampaigns(List<Long> campaignIds);
}
I've read that a network request should be made with "Flowable
", because of the backpressure management since it's a 'cold observable'. On the other hand, I know the result of the request will be success (with the response) or error, so I don't know if I should use Flowable
or Single
or even Observable
.
Furthermore, I have a database accesses like this:
public interface UserRepository extends Repository {
Observable<Void> saveUser(String username, String hashedPassword, boolean logged, User user);
...
Observable<User> findUser(String username, String hashedPassword);
}
I don't know if I should use Completable
/Flowable
/Observable
in saveUser
method and Single
/Flowable
/Observable
in findUser
method.
Upvotes: 42
Views: 16478
Reputation: 2824
Observable
(service) is emitting items at a faster rate than your observer (client) then you should use Flowable
to benefit from the back pressure mechanism. Hot ObservableSingle
or Maybe
. The difference is that if you want to handle the case where the service send no response or error in this case Single
is better to use by leveraging the onError()
callback. If you don't case if your service will fail or succeed and you don't mind an empty emission and go for Maybe
.WRITE
requests return nothing (only if you want to ensure your data by returning a boolean) in this use case I would use Completable
to execute the action and call onComplete()
at the end.Upvotes: 0
Reputation: 3970
Hmm...
I think the question isn't a trivial one while you have faced a more complex situation.
Eg. Save user (REST) > Save user (SQLlite)
You may want to chain Rx streams into one.
So either you declare
1.
Flowable<Response<Void>> saveUser(String username, String hashedPassword, boolean logged, User user);
and then use some of: flatMap, concatMap, switchMap
2.
... or I think maybe more preferable to not confuse class responsibility (you may use the same code in many places)
Single<Response<Void>> saveUser(String username, String hashedPassword, boolean logged, User user);
RestService.saveUser(...)
.toFlowable() // Transform into Flowable
.switchMap{ saveToDB() }
.subscribeBy{ ... }
.addTo( yourDisposable )
3.
By the way, I suggest to not use Completable in case if you want to have nice error handling. You may easily wrap Retrofit.Response<Body>
in Single
or Flowable
to take advantage of the code response from server
Upvotes: 0
Reputation: 44965
Backpressure occurs when an Observable
is emitting items more rapidly than an operator or subscriber can consume them.
Knowing that, Backpressure is not an issue in your case as your Observable
will emit only one item so Flowable
is not a good candidate.
So the real question is whether to use Completable
or Observable
for saveUser
and Single
or Observable
for findUser
and here as only one result is expected (success or failure) for the sake of simplicity and clarity of your API, you should definitively use Completable
/Single
otherwise it will be hard to understand that only one value will be emitted which could be misleading to your API users.
Upvotes: 18
Reputation: 486
Cardinality is one way of understanding the differences between Completable, Maybe and Single:
Maybe<T>
is just an Observable with cardinality 0 or 1 i.e. it represents a result which can either be present or not.Single<T>
is an Observable that always returns a result i.e. a cardinality of 1.Completable
can be interpreted sort of as a Observable<Void>
i.e. a cardinality of 0.So in your case you can change the signature of the repository in this way:
Completable saveUser(...);
Single<User> findUser(...);
(I didn't mention Flowable
s which are like Observable
s with backpressure).
Upvotes: 10
Reputation: 4056
As I understand, you should use Single: when you are pretty sure that you are going to get an item, otherwise you would get an error. Eg: GET - card/:id
Maybe: is the correct solution if you are no so sure if you will get an item. Eg: GET - card?license-plate=xvar3
Completable: when you only want to know if the action was made. Eg: PUT or DETELE
Observable: when the quantity of items is not so large.
Flowable: when you don't konw the quantity of items that you will get.
Upvotes: 3
Reputation: 4258
Backpressure is what you get when a source Observable
is emitting items faster than a Subscriber
can consume them. It's most often a concern with hot observables, not cold ones like your network requests.
I think you should use Completable
instead of Observable<Void>
in your saveUser
method, and use Single
for all places where you follow a request/response or input/output pattern. Observable
should be used when you actually want a continuous stream of events.
Upvotes: 39