Search code examples
androidrx-javarx-java2combinelatest

How to ignore one of observables in combineLatest, but have its latest available in the combiner function?


I have this real world scenario.

I have a ReaderConfig object, which is a dumb tuple of ReaderTheme, ReaderFont, ReaderFontSize. Its changes will trigger the readerConfigObservable which then redraws stuff.

So the solution sofar is

combineLatest(themeObservable, fontObservable, fontSizeObservable, 
    (theme, font, fontSize) -> new ReaderConfig(theme, font, fontSize))

However, because this is android, ReaderTheme sets some android R.theme. stuff, which need to restart Activity for them to take effect. So I need to expose the themeObservable by it self also

themeObservable.subscribe(__ -> activity.recreate())

Since it restarts the activity, theres no need for it to trigger the combineLatest, which triggers redraw and allocates resources, only to be disposed of 1 second later because of the restart.

So only fontObservable and fontSizeObservable changes should trigger the combineLatest, HOWEVER I do need the latest themeObservable value in order to construct the ReaderConfig object.

My workaround is this

public Observable<ReaderConfig> readerConfigObservable() {
        return Observable.combineLatest(
                mFontRelay, mFontSizeRelay, (__, ___) -> createReaderConfig());
    }

    public ReaderConfig createReaderConfig() {
        return new ReaderConfig(mThemeRelay.getValue(), mFontRelay.getValue(), mFontSizeRelay.getValue());
    }

So basically it pulls the themeObservable in the combiner function which is not really reactive, is there any proper solution for this exception use case?


Solution

  • I think this could be solved using withLatestFrom(...):

    Merges the specified ObservableSource into this ObservableSource sequence by using the resultSelector function only when the source ObservableSource (this instance) emits an item.

    See the marbles diagram: http://rxmarbles.com/#withLatestFrom

    Example:

    .combineLatest(fontObservable, fontSizeObservable, 
        (font, size) -> new FontConfig(font, size))
    .withLatestFrom(themeObservable,
        (fontConfig, theme) -> new ReaderConfig(theme, fontConfig.font, fontConfig.size))