I am using RxJava in my Android app and I want to load data from the database.
In this way, I am creating a new Observable using Observable.create() which returns a list of EventLog
public Observable<List<EventLog>> loadEventLogs() {
return Observable.create(new Observable.OnSubscribe<List<EventLog>>() {
#Override
public void call(Subscriber<? super List<EventLog>> subscriber) {
List<DBEventLog> logs = new Select().from(DBEventLog.class).execute();
List<EventLog> eventLogs = new ArrayList<>(logs.size());
for (int i = 0; i < logs.size(); i++) {
eventLogs.add(new EventLog(logs.get(i)));
}
subscriber.onNext(eventLogs);
}
});
}
Though it works correctly, I read that using Observable.create() is not actually a best practice for Rx Java (see here).
So I changed this method in this way.
public Observable<List<EventLog>> loadEventLogs() {
return Observable.fromCallable(new Func0<List<EventLog>>() {
#Override
public List<EventLog> call() {
List<DBEventLog> logs = new Select().from(DBEventLog.class).execute();
List<EventLog> eventLogs = new ArrayList<>(logs.size());
for (int i = 0; i < logs.size(); i++) {
eventLogs.add(new EventLog(logs.get(i)));
}
return eventLogs;
}
});
}
Is this a better approach using Rx Java? Why? What is actually the difference among the two methods?
Moreover, since the database load a list of elements, makes sense to emit the entire list at once? Or should I emit one item at a time?
The two methods may look like similar and behave similar but fromCallable deals with the difficulties of backpressure for you whereas the create version does not. Dealing with backpressure inside an OnSubscribe implementation ranges from simple to outright mind-melting; however, if omitted, you may get MissingBackpressureExceptions along asynchronous boundaries (such as observeOn) or even on continuation boundaries (such as concat).
RxJava tries to offer proper backpressure support for as much factories and operators as possible, however, there are quite a few factories and operators that can't support it.
The second problem with manual OnSubscribe implementation is the lack of cancellation support, especially if you generate a lot of onNext calls. Many of these can be replaced by standard factory methods (such as from) or helper classes (such as SyncOnSubscribe) that deal with all the complexity for you.
You may find a lot of introductions and examples that (still) use create for two reasons.
It is much easier to introduce push-based datastreams by showing how the push of events work in an imperative fashion. In my opinion, such sources spend too much time with create proportionally instead of talking about the standard factory methods and showing how certain common tasks (such as yours) can be achieved safely.
Many of these examples were created the time RxJava didn't require backpressure support or even proper synchronous cancellation support or were just ported from the Rx.NET examples (which to date doesn't support backpressure and synchronous cancellation works somehow, courtesy of C# I guess.) Generating values by calling onNext was worry-free back then. However, such use does lead to buffer bloat and excessive memory usage, therefore, the Netflix team came up with a way of limiting the memory usage by requiring observers to state how many items are they willing to proceed. This became known as backpressure.
For the second question, namely if one should create a List or a sequence of values, it depends on your source. If your source supports some kind of iteration or streaming of individual data elements (such as JDBC), you can just hook onto it and emit one by one (see SyncOnSubscribe). If it doesn't support it or you need it in List form anyway, then keep it as it is. You can always convert between the two forms via toList and flatMapIterable if necessary.
As it's explain in the response you linked, with Observable.create you'll may need to violate the advanced requirements of RxJava.
For example, you'll need to implement backpressure, or how to unsubscribe.
In you case, you want to emit an item, without having to deal with backpressure or subscription. So Observable.fromCallable is a good call. RxJava will deal with the rest.
Related
I am looking for a way to update specific items in my PagingDataAdapter from the Paging 3 library. The recommended way at the moment seems to be to invalidate the PagingSource but this causes the adapter to fetch the whole data set again, which is not efficient and also shows my loading spinner.
However, I noticed that I can access and modify items in the adapter using the peek() method and it seems to work quite well. Am I missing anything here? Will this fall apart in certain scenarios? I know that it's good practice to keep data classes immutable but this approach makes my life a lot easier.
Here is an example of my usage and it seems to work quite well:
viewModel.chatMessageUpdateEvents.collect { messageEvent ->
when (messageEvent) {
is FirestoreChatMessageListener.ChatMessageUpdateEvent.MessageUpdate -> {
val update = messageEvent.chatMessage
val historyAdapterItems = chatMessagesHistoryAdapter.snapshot().items
val updatedMessage =
historyAdapterItems.find { chatMessage ->
chatMessage.documentId == messageEvent.chatMessage.documentId
}
if (updatedMessage != null) {
val messagePosition = historyAdapterItems.indexOf(updatedMessage)
chatMessagesHistoryAdapter.peek(messagePosition)?.unsent = update.unsent
chatMessagesHistoryAdapter.peek(messagePosition)?.imageUrl = update.imageUrl
chatMessagesHistoryAdapter.notifyItemChanged(messagePosition)
}
}
}
}
I replied in a separate comment but wanted to post here for visibility.
This is really not recommended and a completely unsupported usage of paging.
One of the primary ways of restoring state if Pager().flow() hasn't been cleaned up (say if ViewModel hasn't been cleared yet) is via the .cachedIn(scope) method, which will cache out-of-date data in your case. This is also the only way to multicast (make the loaded data in PagingData re-usable) for usage in Flow operations like .combine() that allow you to mix transformations with external signals.
You'll also need to handle races between in-flight loads, what happens if you get a messageEvent the same time an append finishes? Who wins in this case and is it possible between taking the .snapshot() a new page is inserted so your notify position is no longer correct?
In general it's much simpler to have a single source of truth and this is the recommended path, so the advice has always been to invalidate on every backing dataset update.
There is an open FR in Paging's issue tracker to support Flow<Item> or Flow<Page> style data to allow granular updates, but it's certainly a farther future thing: https://issuetracker.google.com/160232968
I'm quite new to reactive programming and I've introduced myself to RxJava2 in Android. For the time being, I've faced easy problems, such as zipping observables. But now, something new cropped up, I'm trying to explain.
Suppose I've got a list of requests Observable<List<Request>>. What I want to do is to call a web service which returns per each request, the list of routes (wrapped in an Observable). I've checked questions like this, but in this case I think I can't flatMap an observable and a list of observables.
How can I do it? Is there any other operator?
You can flatten the Observable<List<Request>> into Observable<Request> using flatMapIterable. Assuming you have a helper method with the signature Observable<List<Route>> getListOfRoutes(Request request) { ... } you can do this:
Observable<List<Request>> obs = ...;
obs.flatMapIterable(l -> l)
.flatMap(request -> getListOfRoutes(request)
.doOnNext(routes -> request.setRoutes(routes))
.map(ign -> request)
)
...
This is assuming that you ultimately want Observable<Request> to be emitted downstream. If you want a different type, you can do something different in the map operator to suit your needs.
I have and Android app with the view class (Fragment, Activity) observing its ViewModel.
The ViewModel exposes methods such as getUserName which returns Observable<String>. Although maybe there is a possibility to find a better name (maybe observeUserName), I'm happy with the current one - it is quite explanatory.
However, here starts the hard part: ViewModel also can tell the view to perform some operation - for example close itself, pop backstack etc. For this case ViewModel defines following method (and corresponging Subject):
class ViewModel {
// other methods, fields
// ViewModel can call returnToPreviousScreen.onComplete()
CompletableSubject returnToPreviousScreen = CompletableSubject.create();
Completable returnToPreviousScreen() { return returnToPreviousScreen; }
}
In my opinion, the method's name is terrible. Hovewer I can not find anything better. Something like observeWhenToReturnToPreviousScreen is maybe more explanatory but hard to read.
So, are there any recommendations or maybe commonly used practices for naming such methods?
There's no universal answer to the naming problem, so the only thing you can get are opinions.
Rule of thumb
My approach to naming in rx-java usually looks at two things:
Does it express a "stream" of emitted events (usually with a plural form of a noun)?
Does it work well with other parts of rx java methods chain, and especially the subscribe method?
Both of the above can be usually simplified to trying to put the name of the method in this sentence:
This code subscribes to {name_of_the_method}.
Examples
A) getUserName
This code subscribes to getUserName.
👎 The sentence does not really make sense because getUserName does not express the stream. Quite on the contrary, it suggests that there is one value that you can get.
getUserName().subscribe()
B) observeUserName
This code subscribes to observeUserName.
👎 Although the method kind-of expresses the stream of events, it does not work well with subscribe. Method exposing the Observable is not a place for information about observing. The consumer of the method will be observing what that method returns.
observeUserName().subscribe()
C) userNames
This code subscribes to userNames.
👎👍 This might work in some cases. It nicely expresses a stream of userName items being emitted and works well with subscribe. It really depends on a particular scenario, because it suggests that you can expect multiple userNames while you really want to observe how a single userName changes.
userNames().subscribe()
C) userNameChanges
This code subscribes to userNameChanges.
👍 This method nicely expresses that there is a stream of items ("change" events) and it works well with subscribe method.
userNameChanges().subscribe()
Return to previous screen
As far as your returnToPreviousScreen case goes, I think I would end up using something like:
This code subscribes to returnRequests().
or
This code subscribes to previousScreenRequests().
or even a singular form as there can only be one event emitted in the stream:
This code subscribes to previousScreenRequest().
(not a topic of a question but I think I would use a Single<Unit> rather than Completable, to express a singular event emission rather than a completion... but maybe that's just me).
Hi I am reading this post https://news.realm.io/news/eric-maxwell-mvc-mvp-and-mvvm-on-android/ where they explained very well about mvc, mvp, mvvm. I undertood how mvp design pattern works.
I don't find any drawback in MVP over MVVM. As they suggested this is issue
Presenter Concerns -> Maintenance - Presenters, just like Controllers, are prone to collecting additional business logic, sprinkled in, over time. At some point, developers often find themselves with large unwieldy presenters that are difficult to break apart.
Can anyone explain what does it means with an example & how it can be resolved using MVVM ?
I'm a big advocate of MVP and haven't really tried MVVM. The drawback of the possibility of a Presenter getting out of control is something I've had experience with but it can be mitigated.
In the example from the post the business logic will be relatively simple. There is likely only one model to deal with and not too much complex logic.
Let's think of a more complicated example though. Say you have an app that sells flowers. Once the user has chosen their bunch of flowers they get taken to the order options screen where they can:
add a message to the flowers
choose a gift vase
select postage addresses
choose a delivery date
Then add some domain requirements:
you can't add a message if they're delivering abroad
some areas have different lead times on delivery
some vases are only available with some flowers
This might not be the best UX but putting that aside you now have a Presenter that has to deal with many different Models (account, address, vases, orders) and can very quickly start taking on many responsibilities beyond simply telling the View what to display and passing events to the Model. This violates the Single Responsibility Principle. Also any time a class starts getting beyond 500 lines I start getting upset.
The solution is relatively simple though. You separate all your separate bits of logic out into UseCase classes. I use a relatively simple base class as follows:
public abstract class UseCase<I, O> {
public static final int NO_STATUS = -1;
public Observable<Integer> getStatus() {
return Observable.just(NO_STATUS);
}
public abstract Observable<O> getAction(I input);
}
You specify an input & output type and inject all the models you need in the constructor in the concrete implementation class. The Presenter takes events and input from the View passes this to the appropriate UseCase, this then does the complex logic with the Model and returns the appropriate data to the Presenter to update the View.
You can send periodic status updates back to your Presenter using the status if needed to update the UI state.
This way your Presenter returns to being a simple conduit for transferring data & events between the View and the Model and the business logic is nicely contained in a separate class for each action.
As in the MVVP introduction in the article said:
MVVM with Data Binding on Android has the benefits of easier testing
and modularity, while also reducing the amount of glue code that we
have to write to connect the view + model.
Main differences of MVP and MVVP are:
View layer: In MVP, your View is totally a dumb and passive View. But in MVVP, your View is more flexible because it can bind to observable.
In MVP, your Presenter takes care almost everything because of dumb View, so it will become really big and complicated gradually. Meanwhile, in MVVP, ViewModel have support from View (its a little bit smart :D), especially Data Binding, you can reduce a part of logic codes.
Therefore, you will write a lot of codes for Presenter and they are logically related in which you will find it difficult to break down.
However, many developers prefer MVP because they do not want some business logic codes being part of XML layout.
I'm still fairly new to RxJava and I'm using it in an Android application. I've read a metric ton on the subject but still feel like I'm missing something.
I have the following scenario:
I have data stored in the system which is accessed via various service connections (AIDL) and I need to retrieve data from this system (1-n number of async calls can happen). Rx has helped me a ton in simplifying this code. However, this entire process tends to take a few seconds (upwards of 5 seconds+) therefore I need to cache this data to speed up the native app.
The requirements at this point are:
Initial subscription, the cache will be empty, therefore we have to wait the required time to load. No big deal. After that the data should be cached.
Subsequent loads should pull the data from cache, but then the data should be reloaded and the disk cache should be behind the scenes.
The Problem: I have two Observables - A and B. A contains the nested Observables that pull data from the local services (tons going on here). B is much simpler. B simply contains the code to pull the data from disk cache.
Need to solve:
a) Return a cached item (if cached) and continue to re-load the disk cache.
b) Cache is empty, load the data from system, cache it and return it. Subsequent calls go back to "a".
I've had a few folks recommend a few operations such as flatmap, merge and even subjects but for some reason I'm having trouble connecting the dots.
How can I do this?
Here are a couple options on how to do this. I'll try to explain them as best I can as I go along. This is napkin-code, and I'm using Java8-style lambda syntax because I'm lazy and it's prettier. :)
A subject, like AsyncSubject, would be perfect if you could keep these as instance states in memory, although it sounds like you need to store these to disk. However, I think this approach is worth mentioning just in case you are able to. Also, it's just a nifty technique to know.
AsyncSubject is an Observable that only emits the LAST value published to it (A Subject is both an Observer and an Observable), and will only start emitting after onCompleted has been called. Thus, anything that subscribes after that complete will receive the next value.
In this case, you could have (in an application class or other singleton instance at the app level):
public class MyApplication extends Application {
private final AsyncSubject<Foo> foo = AsyncSubject.create();
/** Asynchronously gets foo and stores it in the subject. */
public void fetchFooAsync() {
// Gets the observable that does all the heavy lifting.
// It should emit one item and then complete.
FooHelper.getTheFooObservable().subscribe(foo);
}
/** Provides the foo for any consumers who need a foo. */
public Observable<Foo> getFoo() {
return foo;
}
}
Deferring the Observable. Observable.defer lets you wait to create an Observable until it is subscribed to. You can use this to allow the disk cache fetch to run in the background, and then return the cached version or, if not in cache, make the real deal.
This version assumes that your getter code, both cache fetch and non- catch creation, are blocking calls, not observables, and the defer does work in the background. For example:
public Observable<Foo> getFoo() {
Observable.defer(() -> {
if (FooHelper.isFooCached()) {
return Observable.just(FooHelper.getFooFromCacheBlocking());
}
return Observable.just(FooHelper.createNewFooBlocking());
}).subscribeOn(Schedulers.io());
}
Use concatWith and take. Here we assume our method to get the Foo from the disk cache either emits a single item and completes or else just completes without emitting, if empty.
public Observable<Foo> getFoo() {
return FooHelper.getCachedFooObservable()
.concatWith(FooHelper.getRealFooObservable())
.take(1);
}
That method should only attempt to fetch the real deal if the cached observable finished empty.
Use amb or ambWith. This is probably one the craziest solutions, but fun to point out. amb basically takes a couple (or more with the overloads) observables and waits until one of them emits an item, then it completely discards the other observable and just takes the one that won the race. The only way this would be useful is if it's possible for the computation step of creating a new Foo to be faster than fetching it from disk. In that case, you could do something like this:
public Observable<Foo> getFoo() {
return Observable.amb(
FooHelper.getCachedFooObservable(),
FooHelper.getRealFooObservable());
}
I kinda prefer Option 3. As far as actually caching it, you could have something like this at one of the entry points (preferably before we're gonna need the Foo, since as you said this is a long-running operation) Later consumers should get the cached version as long as it has finished writing. Using an AsyncSubject here may help as well, to make sure we don't trigger the work multiple times while waiting for it to be written. The consumers would only get the completed result, but again, that only works if it can be reasonably kept around in memory.
if (!FooHelper.isFooCached()) {
getFoo()
.subscribeOn(Schedulers.io())
.subscribe((foo) -> FooHelper.cacheTheFoo(foo));
}
Note that, you should either keep around a single thread scheduler meant for disk writing (and reading) and use .observeOn(foo) after .subscribeOn(...), or otherwise synchronize access to the disk cache to prevent concurrency issues.
I’ve recently published a library on Github for Android and Java, called RxCache, which meets your needs about caching data using observables.
RxCache implements two caching layers -memory and disk, and it counts with several annotations in order to configure the behaviour of every provider.
It is highly recommended to use with Retrofit for data retrieved from http calls. Using lambda expression, you can formulate expression as follows:
rxCache.getUser(retrofit.getUser(id), () -> true).flatmap(user -> user);
I hope you will find it interesting :)
Take a look at the project below. This is my personal take on things and I have used this pattern in a number of apps.
https://github.com/zsiegel/rxandroid-architecture-sample
Take a look at the PersistenceService. Rather than hitting the database (or MockService in the example project) you could simply have a local list of users that are updated with the save() method and just return that in the get().
Let me know if you have any questions.