RxJava- Placing several Observable values in a static body of text?

252 Views Asked by At

I have heard several reactive programming folks say "don't break the monad, just continue it". I see the merit in this. There are still certain instances I'm confused about, especially when the Observable is finally consumed or subscribed to. This is even more confusing when several observables have to be consumed at once, and it doesn't feel very practical to combine them into a single observable.

Let's say for instance I have a TrackedAircraft type. Some of its properties are final while other properties are Observable.

public interface TrackedAircraft {

    public int getFlightNumber();
    public int getCapacity();
    public Observable<String> getOrigin();
    public Observable<String> getDestination();
    public Observable<Integer> getMileage();
    public Observable<Point> getLocation();

}

I could wire this to a GUI pretty easily, and just subscribe controls to be updated with each emission of each property. But what about an email or a body of static text? This is not as straightforward because the only way I can think of not breaking the monad is to combine all the observables which sounds like a pain especially if I have an Observable emitting TrackedFlights.

Is it okay to block in this situation? Or is there a more monadic way to accomplish this I haven't thought of?

public static String generateEmailReportForFlight(TrackedAircraft flight) { 
    return new StringBuilder().append("FLIGHT NUMBER: ").append(flight.getFlightNumber()).append("\r\n")
    .append("CAPACITY: ").append(flight.getCapacity()).append("\r\n")
    .append("ORIGIN: ").append(flight.getOrigin() /*What do I do here without blocking?*/)
    .append("DESTINATION: ").append(flight.getDestination() /*What do I do here without blocking?*/)
    .append("MILEAGE: ").append(flight.getMileage() /*What do I do here without blocking?*/)
    .append("LOCATION: ").append(flight.getLocation() /*What do I do here without blocking?*/)
    .toString();
}

///

Observable<TrackedAircraft> trackedFlights = ...;
trackedFlights.map(f -> generateEmailReportForFlight(f));
1

There are 1 best solutions below

1
On BEST ANSWER

You can use flatMap + combineLatest:

Observable<TrackedAircraft> trackedFlights = ...

trackedFlights
.flatMap(flight -> emailReport(flight))
.subscribe(msg -> sendEmail(msg));

Observable<String> emailReport(TrackedAircraft flight) {
    return Observable.combineLatest(
        flight.getOrigin(), 
        flight.getDestination(), 
        flight.getMileage(), 
        flight.getLocation()
        (origin, destination, mileage, location) -> {
             return new StringBuilder()
             .append("FLIGHT NUMBER: ").append(flight.getFlightNumber())
             .append("\r\n")
             .append("CAPACITY: ").append(flight.getCapacity())
             .append("\r\n")
             .append("ORIGIN: ").append(origin)
             .append("\r\n")
             .append("DESTINATION: ").append(destination)
             .append("\r\n")
             .append("MILEAGE: ").append(mileage)
             .append("\r\n")
             .append("LOCATION: ").append(location)
             .toString();
        }
    )
}