2017-04-01 49 views
5

Próbuję przeprowadzić migrację z RxJava1 do RxJava2. Zastępuję wszystkie części kodu, w których poprzednio miałem Observable<Void> do Compleatable. Jednak wystąpił jeden problem z kolejnością wywołań strumieniowych. Kiedy poprzednio zajmowałem się Observables i korzystałem z map i płaskich map, kod działał "zgodnie z oczekiwaniami". Jednak operator andthen() wydaje się działać nieco inaczej. Oto przykładowy kod upraszczający sam problem.Kolejność wywołań RxJava2 z wykonalnym operatorem i operatorem

public Single<String> getString() { 
    Log.d("Starting flow..") 
    return getCompletable().andThen(getSingle()); 
} 

public Completable getCompletable() { 
    Log.d("calling getCompletable"); 
    return Completable.create(e -> { 
       Log.d("doing actuall completable work"); 
       e.onComplete(); 
      } 
    ); 
} 

public Single<String> getSingle() { 
    Log.d("calling getSingle"); 
    if(conditionBasedOnActualCompletableWork) { 
     return getSingleA(); 
    }else{ 
     return getSingleB(); 
    } 
} 

Co widzę w dziennikach w końcu jest:

1-> Log.d("Starting flow..") 
    2-> Log.d("calling getCompletable"); 
    3-> Log.d("calling getSingle"); 
    4-> Log.d("doing actuall completable work"); 

I jak można chyba wymyślić spodziewałbym linia 4 zostać wywołana przed linii 3 (później nazwa andthen() operatora sugerują, że kod będzie nazywać się "po" Komplecie kończy pracę). Wcześniej tworzyłem Observable<Void> używając operatora Async.toAsync(), a metoda, która jest teraz nazywana getSingle była w strumieniu flatMap - działała tak, jak oczekiwałam, więc Log 4 pojawił się przed 3. Teraz próbowałem zmienić sposób, w jaki jest tworzony Compleatable - jak przy użyciu fromAction lub fromCallable, ale zachowuje się tak samo. Nie mogłem też znaleźć innego operatora, który mógłby zastąpić andthen(). Podkreślenie - metoda musi być Completable, ponieważ nie ma żadnej rzeczy, która w pełni powróciłaby do formy - zmienia preferencje aplikacji i inne ustawienia (i jest używana tak, jak na całym świecie w większości działa "zgodnie z oczekiwaniami"), a te zmiany są potrzebne później w strumieniu. Próbowałem też owinąć metodę getSingle(), aby w jakiś sposób utworzyć Single i przenieść instrukcję if wewnątrz bloku create, ale nie wiem jak używać metod getSingleA/B(). I potrzebuję ich użyć, ponieważ mają swoją złożoność i nie ma sensu powielać kodu. Ktoś ma jakiś pomysł, jak to zmienić w RxJava2, więc zachowuje się tak samo? Istnieje wiele miejsc, w których polegam na pracy Compleatable, aby zakończyć, zanim przejdę do przodu ze strumieniem (jak odświeżanie tokena sesji, aktualizacja db, preferencje itd. - nie ma problemu w RxJava1 przy użyciu flatMap).

+0

Czy rozumiesz, że wywołanie 'getSingle()' wykonuje się natychmiast, a nie po zakończeniu "Completable" zwróconego przez 'getCompletable'? – akarnokd

Odpowiedz

1

Można użyć defer:

getCompletable().andThen(Single.defer(() -> getSingle())) 

ten sposób, że nie od razu wykonać zawartość getSingle() ale tylko wtedy, gdy Completable wypełnia i andThen przełącza do Single.

+0

Dziękuję za wskazówkę, uznałem odpowiedź za pomocną - rozwiązuje problem. Chociaż muszę powiedzieć, że wygląda jak obejście tego rozwiązania. Wciąż jestem zdziwiony, dlaczego zachowanie zmieniło się w porównaniu z wersją RxJava1, w której użyłem flatMap, a callbacks były w kolejności, jakiej oczekiwałem. Nie znalazłem żadnych informacji na ten temat w sekcji "co nowego" dokumentacji RxJava2. –