RxJava에서 Observable을 연결할 때 변수를 전달하는 방법은 무엇입니까?


80

RxJava를 사용하여 비동기 작업을 연결하고 있으며 몇 가지 변수를 다운 스트림으로 전달하고 싶습니다.

Observable
   .from(modifications)
   .flatmap( (data1) -> { return op1(data1); })
   ...
   .flatmap( (data2) -> { 
       // How to access data1 here ?
       return op2(data2);
   })

일반적인 패턴처럼 보이지만 정보를 찾을 수 없습니다.

답변:


65

Couchbase 포럼에서 얻은 조언은 중첩 된 Observable을 사용하라는 것입니다.

Observable
   .from(modifications)
   .flatmap( (data1) -> { 
       return op1(data1)
           ...
           .flatmap( (data2) -> { 
               // I can access data1 here
               return op2(data2);
           })
   });

편집 : 가장 권장되는 것처럼 보이므로 수락 된 답변으로 표시하겠습니다. 처리가 너무 복잡해서 모든 것을 중첩 할 수없는 경우 함수 호출로 솔루션을 확인할 수도 있습니다.


이것이 제가 자주하는 일이며 지금까지 잘 작동했습니다.

흠 이것은 "스트림 외부에 데이터 저장"과 비교할 때 크게 다르지 않습니다.
ror

18

또 다른 가능성은 결과 매핑하는 것이다 op1A와 org.apache.commons.lang3.tuple.Pair함께 그 변수와 패스를 포함하는을 :

Observable
   .from(modifications)
   .flatmap( (data1) -> {
       return op1(data1).map( obj -> { return Pair.of(data1,obj); });
   })
   ...
   .flatmap( (dataPair) -> { 
       // data1 is dataPair.getLeft()
       return op2(dataPair.getRight());
   })

작동하지만 Pair / Triple / ... 안에 변수를 숨기는 것이 약간 불편하고 Java 6 표기법을 사용하면 매우 장황 해집니다.

더 나은 솔루션이 있는지 궁금합니다. RxJava 연산자가 도움이 될 수 있습니까?


2
이 일을하는 데 아무런 문제가 없다고 생각하지만 페어 클래스에 도달해야 할 때마다 뭔가 잘못하고 있다고 느낍니다. 내가 사용한 횟수, 내 도메인에 대해 더 잘 이해하게되면 나중에 리팩터링했습니다.

이것은 쓰레기 메이커의 톤 만들 것입니다하지만, 나에게 온 솔루션입니다 Pair단지 유지하기 위해 인스턴스를 data1옆에 obj. 나는 combine작동 하는지 궁금합니다 .
scorpiodawg

7

flatmap은 두 번째 인수를 취할 수 있습니다.

Observable.just("foo")
                .flatMap(foo -> Observable.range(1, 5), Pair::of)
                .subscribe(pair -> System.out.println("Result: " + pair.getFirst() + " Foo: " + pair.getSecond()));

출처 : https://medium.com/rxjava-tidbits/rxjava-tidbits-1-use-flatmap-and-retain-original-source-value-4ec6a2de52d4


쌍을 가져 오는 방법?
Dyno Cris

@DynoCris 직접 작성하거나 일부 libs에서 가져올 수 있습니다 (단지 google java + pair)
Sisyphus

6

한 가지 가능성은 함수 호출을 사용하는 것입니다.

private static Observable<T> myFunc(final Object data1) {
    return op1(data1)
        ...
        .flatmap( (data2) -> { 
            // I can access data1 here
            return op2(data2);
        });
}

Observable
   .from(modifications)
   .flatmap( (data1) -> { return myFunc(data1); })

하지만 내가 틀렸다면 정정 해 주지만 반응 프로그래밍 방식이 아닌 것 같습니다.


2
이것이 첫 번째 옵션과 많이 다른가요?
Will

@Will yes 중첩 호출을 사용하는 것과 기능적으로 유사하다고 생각합니다. 복잡한 처리의 경우 결국 나쁜 선택은 아닙니다.
Julian Go

3

사실 우리는 콜 체인을 단순화하는 라이브러리를 가지고 있습니다.

https://github.com/pakoito/Komprehensions

Gradle 종속성으로 추가 :

implementation 'io.reactivex.rxjava2:rxjava:2.2.1'
implementation 'com.github.pakoito.Komprehensions:komprehensions-rx2:1.3.2'

사용법 (Kotlin) :

val observable = doFlatMap(
    { Observable.from(modifications) },
    { data1 -> op1(data1) },
    { data1, data2 -> op2(data2) },
    { data1, data2, data3 -> op3(data1, data2, data3) }
)

0

이 스레드에 대한 솔루션은 작동하지만 복잡한 체인의 경우 코드를 읽기 어렵게 만들고 여러 값을 전달해야했고 모든 매개 변수가있는 개인 클래스를 만드는 것이 었습니다.이 방법으로 코드를 더 읽기 쉽게 찾을 수 있습니다.

private class CommonData{
   private string data1;
   private string data2;

   *getters and setters*
}
...
final CommonData data = new CommonData();
Observable
   .from(modifications)
   .flatmap( (data1) -> { 
       data.setData1(data1);
       return op1(data1); 
   })
   ...
   .flatmap( (data2) -> { 
       data2 = data.getData1() + "data 2... ";
       data.setData2(data2);
       return op2(data2);
   })

도움이 되길 바랍니다


2
불행히도 이것은 스레드로부터 안전하지 않을 수 있습니다 (코드에 따라 RxJava는 여러 스레드에서 계산을 실행합니다)
Julian Go

내가 혼란 스러워요, 왜 개인, 비 정적 변수는 스레드 - "안전하지 않은"것
josesuero

1
RxJava가 데이터를 flatmap ()하기 위해 여러 스레드를 생성하는 경우 CommonData 인스턴스는 정적이 아니더라도 스레드간에 공유됩니다. (현재 스레드와 CommonData 값을 표시하는 일부 로깅으로 테스트 할 수 있어야합니다.)
Julian Go

다음과 같은 작업을 수행해야하기 때문에 다른 해결책을 찾아야합니다. if (boolean) return observer1 else return observer2; 당신은 둘 다에 flatmap해야 할 것입니다 .. 나쁜
josesuero

0

나는 이것이 오래된 질문이라는 것을 알고 있지만 RxJava2 및 람다를 사용하면 다음과 같이 사용할 수 있습니다.

Observable
.from(modifications)
.flatMap((Function<Data1, ObservableSource<Data2>>) data1 -> {
                        //Get data 2 obeservable

                            return Observable.just(new Data2())
                        }
                    }, Pair::of)

다음 흐름 (플랫 맵 / 맵)에서 출력 쌍은 (data1, data2)입니다.


-2

"전역"변수를 사용하여이를 달성 할 수 있습니다.

 Object[] data1Wrapper = new Object[]{null};
 Object[] data2Wrapper = new Object[]{null};
 Observable
    .from(modifications)
    .flatmap(data1 -> {
        data1Wrapper[0] = data1;
        return op1(data1)
     })
      ...
    .flatmap(data2 -> { 
        // I can access data1 here use data1Wrapper[0]
        Object data1 = data1Wrapper[0];
        data2Wrapper[0] = data2;
        return op2(data2);
     })

4
이것은 나쁜 조언입니다. 스트림 외부에 데이터를 저장하지 말고 SwitchMap 또는 유사한 접근 방식을 사용하여 데이터를 전달하십시오. 이것은 반 패턴입니다.
lsrom
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.