There is probably a better way to go, but you could attach a timestamp of emission to each event, determine which of them was last and emit the rest. Identify those events by the observable ( field ) from which they have come and decide by the element which is missing in the list.
mObservableEditTextA = RxTextView.textChanges(mEditTextA)
.debounce(500, TimeUnit.MILLISECONDS) // So we don't flood the heap with lots of object construction, creating performance overhead due to garbage collection
.map(text -> Pair.create(new Date(), text));
mObservableEditTextB = RxTextView.textChanges(mEditTextB)
.debounce(500, TimeUnit.MILLISECONDS)
.map(text -> Pair.create(new Date(), text));
mObservableEditTextC = RxTextView.textChanges(mEditTextC)
.debounce(500, TimeUnit.MILLISECONDS)
.map(text -> Pair.create(new Date(), text));
Observable.combineLatest(mObservableEditTextA, mObservableEditTextB, mObservableEditTextC, (fieldAPair, fieldBPair, fieldCPair) -> {
firstField = ...;
secondField = ...;
// from timestamps determine which of the fields emitted last and return the other two with identifiers
return Arrays.asList(Pair.create(firstFieldIdentifier, firstField), Pair.create(secondFieldIdentifier, secondField));
})
.subscribe(result -> {
/* result is always a list of 2 items, more specifically
pairs of an identification in first position and new text
in the second.
Here you can look for the missing field in the list and
compute it from the other two */
})
The logic for determining which one do you want to compute is duplicated here. I did that just for the reason of not having to wrap those objects in a new object and nested Pairs lose readability.
You could however treat the position in a list as an identifier for the field although that is prone to mistakes.
Any of those approaches would move the determining logic from both subscriber and combineLatest operator only to subscriber itself. Your call.