Example of GroupBy

.groupBy() is a perfect tool for this. Given a key function, the .groupBy() will emit a new set of Observables (so we will have an Observable of Observables) which will contain items that had the same value that was returned by the key function.

Let's see an example:

Observable.just(
new StockUpdate("APPL", BigDecimal.ONE, new Date(), ""),
new StockUpdate("GOOG", BigDecimal.ONE, new Date(), ""),
new StockUpdate("APPL", BigDecimal.ONE, new Date(), ""),
new StockUpdate("APPL", BigDecimal.ONE, new Date(), "")
)
.groupBy(StockUpdate::getStockSymbol)
.flatMapSingle(groupedObservable ->
groupedObservable.count())
.subscribe(this::log);

This will result in the following output:

APP: main:3
APP: main:1

This means three items for APPL stock in one Observable and one item for GOOG in another Observable.

We can use the same idea to make emit values for the stocks only when they have changed:

Observable.interval(0, 5, TimeUnit.SECONDS)
.flatMapSingle(i -> yahooService.yqlQuery(query, env))
.map(r -> r.getQuery().getResults().getQuote())
.flatMap(Observable::fromIterable)
.map(StockUpdate::create)
.groupBy(StockUpdate::getStockSymbol)
.flatMap(Observable::distinctUntilChanged)

Here, we have added these lines:

.groupBy(StockUpdate::getStockSymbol)
.flatMap(Observable::distinctUntilChanged)

Alternatively, we can use lambdas instead of method references to make code easier to read (personal preference):

.groupBy(stockUpdate -> stockUpdate.getStockSymbol())
.flatMap(groupObservable -> groupObservable.distinctUntilChanged())

The first line produces a group of Observables that will contain StockUpdate, which have the same symbol in their respective group. The following line then unwraps the Observables back into regular StockUpdate items:

.flatMap(groupObservable -> groupObservable.distinctUntilChanged())

However, before the unwrapping is done, the following call ensures that each of the respective groups will only return items when they are different from the previous value:

.distinctUntilChanged()

The only thing that needs to be done now is to implement the .equals() and, preferably, .hashCode() methods on the StockUpdate object:

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

StockUpdate that = (StockUpdate) o;

if
(!stockSymbol.equals(that.stockSymbol)) return false;
if (!price.equals(that.price)) return false;
if (!twitterStatus.equals(that.twitterStatus)) return false;
return id != null ? id.equals(that.id) : that.id == null;

}

@Override
public int hashCode() {
int result = stockSymbol.hashCode();
result = 31 * result + price.hashCode();
result = 31 * result + twitterStatus.hashCode();
result = 31 * result + (id != null ? id.hashCode() : 0);
return result;
}

Usually, this is easy to do in modern IDEs, such as Android Studio, by utilising built in tools. On Android Studio, one can use the given menu to do that:

Code->Generate...->equals() and hashCode()

Finally, the line that we used for duplicate filtering can be removed as it isn't necessary anymore (it was useful as a learning example though):

.filter(update -> !stockDataAdapter.contains(update))
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.251.128