2

I created an Observable that emits text from edittext. Then in using the switchmap operator, I create a Single that looks for a match in the file.

Here I subscribe:

compositeDisposable.add(getEditTextObservable(editText)
    .debounce(500, TimeUnit.MILLISECONDS)
    .map(String::toLowerCase)
    .filter(s -> !TextUtils.isEmpty(s))
    .switchMapSingle(s -> textCutter.getSearchResult(s))
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe()
);

Here is the search:

public Single<List<TextCut>> getSearchResult(String searchRequest) {
    return Single.fromCallable(() -> textGen.getCutList(searchRequest));
}

As a result, I get that each request is executed in turn. For example, if I enter the query "dog", and then "cat", as a result I get both "dog" and "cat". Although I expected to get only the "cat"

For example:
input: dog
"dog" in progress...
input: cat
output: [result of 'dog']
"cat" in progess...
output: [result of 'cat']

What I expected to get:
input: dog
"dog" in progress...
input: cat
"dog" canceled...
"cat" in progess...
output: [result of 'cat']

pixwire
  • 116
  • 6
  • Are you sure this is what is happening? Maybe by the time the "cat" single is executed, the "dog" one has already completed. – gpunto May 04 '19 at 11:28
  • @gpunto if during the search for "dog" perform a new search for "cat", then first I get the result for "dog", then for "cat". if the request for "dog" takes 1 minute, then only after 1 minute will I get the result for "cat" – pixwire May 04 '19 at 11:38

1 Answers1

1

Having tested in isolation the switchMapSingle operator, using a similar stream of events as yours I cannot find any problem with the swtichMapSingle operator - it would skip when it should skip and emit when it should - I also tried various ways of threading, but all honoured the operator functionality. There must be a problem elsewhere.

Test code run (important part is from debounce onwards, comments added to show expected results) :

public static void main(String... args) {
    final AtomicInteger aInt = new AtomicInteger();
    final AtomicBoolean aBool = new AtomicBoolean(true);

    Observable.just(0)
            .map(i -> {
                final int i2 = i + aInt.incrementAndGet();
                // simulate interval events even every 200 millis, odds every 400 millis
                Thread.sleep(i2 % 2 == 0 ? 200 : 400);
                return i2;
            })
            .repeat()
            // skip all odd numbers
            .debounce(300, MILLISECONDS)
            .switchMapSingle(i3 ->
                    // toggle between 0 and 2 second delay - every 2 second delay dropped (every other even number)
                    Single.just(i3).delay(aBool.getAndSet(!aBool.get())? 0 : 2_000, MILLISECONDS))
            .subscribeOn(Schedulers.io())
            .observeOn(Schedulers.single())
            // expected out - every other even number i.e 2, 6, 10, 14 ..
            .subscribe(i4 -> System.out.println(String.format("Value : %d", i4)));

    try {
        Thread.sleep(60_000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

output :

Value : 2
Value : 6
Value : 10
Value : 14
Value : 18
Value : 22
Value : 26

To confirm when using flatMapSingle that no events are missed output is also as expected - out of order emissions would be the emissions dropped by switchMapSingle

Output with flatMapSingle :

Value : 2
Value : 6
Value : 10
Value : 4    // dropped with switch map single
Value : 14
Value : 8    // dropped with switch map single
Value : 18
Value : 12   // dropped with switch map single
Mark
  • 9,604
  • 5
  • 36
  • 64