programing

Rxandroid SubscribeOn과 ObservateOn의 차이점은 무엇입니까?

goodsources 2022. 10. 11. 22:54
반응형

Rxandroid SubscribeOn과 ObservateOn의 차이점은 무엇입니까?

Rx-java와 Rxandroid2를 배우고 있는데 SubscribeOn과 ObservateOn의 주요 차이점이 무엇인지 혼란스러울 뿐입니다.

SubscribeOn은 관찰 가능이 작동할 스케줄러를 지정합니다.관찰자는 관찰 가능 여부를 관찰할 스케줄러를 지정합니다.

따라서 기본적으로 SubscribeOn은 대부분 백그라운드 스레드에서 구독(실행됨)되며(관찰 가능을 기다리는 동안 UI 스레드를 차단하지 않음), ObserveOn에서도 결과를 메인 스레드에서 관찰하려고 합니다.

비동기 태스크에 익숙한 경우 Subscribe On은 doInBackground 메서드와 비슷하고 관찰 On은 onPost에 유사합니다.실행...

의 답변이 jargons로 가득 찬 경우:

dr;dr

 Observable.just("Some string")                 
           .map(str -> str.length())              
           .observeOn(Schedulers.computation())   
           .map(length -> 2 * length)   
           .observeOn(AndroidSchedulers.mainThread())
           .subscribeOn(Schedulers.io())
           .subscribe(---)

관측 가능한 것을 관찰합니다...I/O 스레드에서 맵 기능을 수행합니다."subscribingOn"그 나사산)...이제 계산 스레드로 전환하여map(length -> 2 * length)마지막으로 감시하는 것을 합니다.observeOn()) 메인 스레드

아무튼.

observeOn()모든 연산자의 스레드를 더 다운스트림으로 변경합니다.사람들은 보통 이렇게 오해한다.observeOn업스트림으로도 기능하지만 그렇지 않습니다.

다음 예에서 더 잘 설명할 수 있습니다.

Observable.just("Some string")                  // UI
       .map(str -> str.length())               // UI
       .observeOn(Schedulers.computation())   // Changing the thread
       .map(length -> 2 * length)            // Computation
       .subscribe(---)                       // Computation

subscribeOn()Observable이 구독될 때 사용되는 스레드에만 영향을 미쳐 해당 스레드에 다운스트림으로 남습니다.

Observable.just("Some String")              // Computation
  .map(str -> str.length())                // Computation
  .map(length -> 2 * length)              // Computation
  .subscribeOn(Schedulers.computation()) // -- changing the thread
  .subscribe(number -> Log.d("", "Number " + number)); // Computation

위치는 subscribeOn()중요하지 않습니다()

왜냐고요? 구독 시간에만 영향을 주기 때문입니다.

와의 subscribeOn

예 : -> 본 - :Observable.create

기재되어 있는 create에서는, 에 지정되어 합니다.subscribeOn.

다른 예로는 '있다'는 것입니다.Observable.just ,Observable.from ★★★★★★★★★★★★★★★★★」Observable.range

참고: 이러한 메서드는 모두 값을 허용하므로 이러한 값을 생성하기 위해 차단 메서드를 사용하지 마십시오. subscribeOn은 영향을 미치지 않습니다.

차단 함수를 사용하려면

Observable.defer(() -> Obervable.just(blockingMenthod())));

중요한 사실:

은 subscribeOn과 함께 할 수 .Subjects

★★subscribeOn:

의 개 subscribeOn물줄기에서는 첫 번째 것만이 실질적인 효과를 발휘합니다.

& subscribe서이이 subscribe subscribe subscribe subscribesubscribeOn

은 그렇게 한다.subscribeOn가 있다Observable.subscribe하지만 특별한 관계가 있는 건 아니에요.서브스크립션 단계에만 영향을 줍니다.

출처 : Tomek Polaskiski (중규모)

요약

  • observeOn콜백의 스레드를 설정하다(예를 들어 내부 코드 블록 등)doOnNext ★★★★★★★★★★★★★★★★★」map.
  • subscribeOn초기화에 대한 스레드를 설정하다(예: "위쪽").doOnSubscribe,Observable.just ★★★★★★★★★★★★★★★★★」Observable.create.
  • 두 방식 모두 여러 번 호출할 수 있으며 각 호출이 이전 메서드를 덮어씁니다.위치가 중요합니다.

예를 들어 이 항목을 살펴보겠습니다. "user1032613" 문자열의 길이를 찾습니다.이것은 컴퓨터에게는 쉬운 작업이 아니기 때문에 앱이 정지되는 것을 피하기 위해 백그라운드 스레드로 고도의 계산을 하는 것은 당연합니다.

감시하다

하면 .observeOn 아래의 모든 콜백을 실행할 스레드를 제어합니다.사용하기 쉽고, 기대한 대로 동작합니다.

예를 들어 메인 UI 스레드에 진행 표시줄을 표시하고 다른 스레드에서 집중/차단 작업을 수행한 다음 메인 UI 스레드로 돌아와 결과를 업데이트합니다.

    Observable.just("user1032613")

            .observeOn(mainThread) // set thread for operation 1
            .doOnNext {
                /* operation 1 */
                print("display progress bar")
                progressBar.visibility = View.VISIBLE
            }

            .observeOn(backThread) // set thread for operation 2 and 3
            .map {
                /* operation 2 */
                print("calculating")
                Thread.sleep(5000)
                it.length
            }

            .doOnNext {
                /* operation 3 */
                print("finished calculating")
            }

            .observeOn(mainThread) // set thread for operation 4
            .doOnNext {
                /* operation 4 */
                print("hide progress bar and display result")
                progressBar.visibility = View.GONE
                resultTextView.text = "There're $it characters!"
            }

            .subscribe()

예에서는 " " " 입니다./* operation 1 */ is is is is is is is is in in is 。mainThread 우리는 을 '우리'를 사용하여 설정하기 입니다.observeOn(mainThread)바로 에 있는 것을 그 후, 「이러다」, 「이러다음에, 「이러다」로 .backThreadobserveOn 한 번 말하면/* operation 2 */그곳으로 달려갑니다.을 하기 전에 않았기 /* operation 3 */, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ,/* operation 2 */으로 우리는 ;라고 부른다.observeOn(mainThread) 한 번 확실히 하기 /* operation 4 */UI를 사용하다

서브스크라이브온

지금까지 공부했는데요.observeOn는 후속 콜백의 스레드를 설정합니다.또또???? 아, 아...Observable 자체 및 그 (「」등)을 지정합니다.just(),create(),subscribe()실행이 필요한 코드도 있습니다.이것이 물줄기를 따라 물체가 전달되는 방법입니다.는 용용 we we we we we we we we wesubscribeOnObservable그 자체입니다.

(「」에 의해 된다)observeOn앞에서 설명한 바와 같이, 디폴트로 코드가 기술되어 있는 스레드(메인 스레드)에서 실행되는 「코드」가 남습니다.

    Observable.just("user1032613")
            .observeOn(mainThread)
            .doOnNext {
            }
            .observeOn(backThread)
            .map {
            }
            .doOnNext {
            }
            .observeOn(mainThread)
            .doOnNext {
            }
            .subscribe()

빈 스레드로 하고 있는이 마음에 들지 않는 는, 「」를 사용할 수 .subscribeOn바꿀 수 있습니다.를 들어, 첫 줄 "" " " " " " " 입니다.Observable.just("user1032613")을 생성하거나 수 .doOnSubscribe그럴 전화하시면 .subscribeOn(backThread)코드 일부를 다른 스레드에 넣습니다.

「 」를 넣는 subscribeOn

이 답변을 쓸 때 '한 번만 콜한다', '위치는 중요하지 않다', '여러 번 콜하면 첫 번째 시간만 카운트된다'는 오해가 있다.많은 연구와 실험을 거쳐, 밝혀졌습니다.subscribeOn를 여러 번 호출할 수 있습니다.

★★★★★★★★★★★★★★★★★★Observable에서는 Builder Pattern('메서드를 연속적으로 연결하는'의 팬시 이름)을 사용합니다.subscribeOn는 역순으로 적용됩니다.따라서, 이 메서드는 그에 있는 코드의 스레드를 설정합니다.정확히 반대입니다.observeOn.

해서 해 볼 수 있어요.doOnSubscribe 이벤트에서 , 서브스크립션 되며,서브스크립션 이벤트에서 실행됩니다.subscribeOn:

    Observable.just("user1032613")
            .doOnSubscribe {
                print("#3 running on main thread")
            }
            .subscribeOn(mainThread) // set thread for #3 and just()
            .doOnNext {
            }
            .map {
            }
            .doOnSubscribe {
                print("#2 running on back thread")
            }
            .doOnNext {
            }
            .subscribeOn(backThread) // set thread for #2 above
            .doOnNext {
            }
            .doOnSubscribe {
                print("#1 running on default thread")
            }
            .subscribe()

Builder Pattern이 코드를 실행하는 방법처럼 위의 예를 아래에서 위로 읽는 것이 논리를 따르는 것이 더 쉬울 수 있습니다.

예에서는 첫 행이 " " " 입니다.Observable.just("user1032613")됩니다.print("#3") 더 존재하지 않기 입니다.subscribeOn이렇게 '첫 착각을 . ' 통화만 '라는 착각을 하게 됩니다.just() ★★★★★★★★★★★★★★★★★」create() 많은 것을 하기 시작하면, 이것은 금방 무너집니다.


각주:

및 ★★★★print()을 위해 다음과되어 있습니다.

val mainThread = AndroidSchedulers.mainThread()
val backThread = Schedulers.computation()
private fun print(msg: String) = Log.i("", "${Thread.currentThread().name}: $msg")

rx java 설명을 이해하기 어려운 경우(예를 들어 나)는 다음과 같습니다.

서브스크라이브온()

Observable.just("something")
  .subscribeOn(Schedulers.newThread())
  .subscribe(...);

등가:

Observable observable = Observable.just("something");
new Thread(() -> observable.subscribe(...)).start();

★★★★★★★★★★★★★★★★★★Observablesubscribe() 여기 ★★★★★★ andsubscribe()스레드에 됩니다.subscribe()이 때문에, 「업스트림」(이전 조작의 스레드에 영향을 줍니다)과거 동작의 스레드에 영향을 줍니다).

감시온()

Observable.just("something")
  .observeOn(Schedulers.newThread())
  .subscribe(...);

등가:

Observable observable = Observable.just("something")
  .subscribe(it -> new Thread(() -> ...).start());

서 ★★★★Observable는 메인 스레드에서 값을 내보내고 리스너 메서드만 개별 스레드에서 실행됩니다.

관찰 가능한 항목에 가입하면 체인의 맨 위까지 이동한 후 다시 아래로 이동하는 흐름이 시작됩니다.서브스크라이브 부분은 위쪽 체인과 관련되고 관찰 부분은 아래쪽 체인과 관련됩니다.

체인 상단에 도달하면 서브스크립션 단계가 기본적으로 완료된 것입니다.이벤트가 송신되기 시작하고 지도, 필터 등의 하향 체인이 호출됩니다.

SubscribeOn은 doOnSubscribe와 같이 배치 위의 구독 호출에 영향을 줍니다.

ObserveOn은 배치 아래의 관찰 호출(예: doOnNext, 맵, 플랫맵 등)에 영향을 줍니다.

둘 다 흐름을 위 또는 아래로 계속하기 위해 사용되는 스레드를 변경합니다.

import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;

import java.util.concurrent.CountDownLatch;

public class SubscribeVsObserveOn {

    public static void main(String[] args) throws InterruptedException {

        System.out.println("Ordinal 0: " + Thread.currentThread().getName());

        final CountDownLatch latch = new CountDownLatch(1);

        Observable
            .just("a regular string.")
            .doOnSubscribe(disposable ->
                System.out.println("Ordinal 2: " + Thread.currentThread().getName()))
            .subscribeOn(Schedulers.newThread())
            .observeOn(Schedulers.newThread())
            .doOnNext(s ->
                System.out.println("Ordinal 3: " + Thread.currentThread().getName()))
            .map(s -> s)
            .doOnSubscribe(disposable ->
                System.out.println("Ordinal 1: " + Thread.currentThread().getName()))
            .subscribeOn(Schedulers.newThread())
            .observeOn(Schedulers.newThread())
            .doOnNext(s ->
                System.out.println("Ordinal 4: " + Thread.currentThread().getName()))
            .map(s -> s)
            .subscribe(s -> latch.countDown());

        latch.await();
    }
}

출력은 다음과 같습니다.

Ordinal 0: main
Ordinal 1: RxNewThreadScheduler-1
Ordinal 2: RxNewThreadScheduler-2
Ordinal 3: RxNewThreadScheduler-3
Ordinal 4: RxNewThreadScheduler-4

이 답변은 새로운 것이 아닙니다.조금만 더 명확히 하고 싶습니다.

  1. 두 개의 스레드가 있다고 가정해 봅시다.

     val pool1 = Executors.newCachedThreadPool { runnable -> Thread(runnable, "Thread 1") }
     val pool2 = Executors.newCachedThreadPool { runnable -> Thread(runnable, "Thread 2") }
    

  1. 한 바와 같이, 변변 as as as as as 。observeOnDownstream , , , , 입니다.subscribeOnUpstream지만만둘면면면면면면면면면면면?이것을 확인하기 위해 로그를 한 줄씩 추가했습니다.

    Observable.just("what if use both")
     .doOnSubscribe { Log.d("Thread", "both, doOnSubscribe A " + Thread.currentThread().name) }
     .doOnNext { Log.d("Thread", "both, doOnNext A " + Thread.currentThread().name) }
     .map {
         Log.d("Thread", "both, map A " + Thread.currentThread().name)
         it + " A"
     }
    
     // observeOn
     .observeOn(Schedulers.from(pool1)) 
    
     .doOnSubscribe { Log.d("Thread", "both, doOnSubscribe B " + Thread.currentThread().name) }
     .doOnNext { Log.d("Thread", "both, doOnNext B " + Thread.currentThread().name) }
     .map {
         Log.d("Thread", "both, map B " + Thread.currentThread().name)
         it + " B"
     }
    
     // subscribeOn
     .subscribeOn(Schedulers.from(pool2)) 
    
     .doOnSubscribe { Log.d("Thread", "both, doOnSubscribe C " + Thread.currentThread().name) }
     .doOnNext { Log.d("Thread", "both, doOnNext C " + Thread.currentThread().name) }
     .map {
        Log.d("Thread", "both, map C " + Thread.currentThread().name)
        it + " C"
      }
    
     // observeOn main
     .observeOn(AndroidSchedulers.mainThread())
     .doOnNext { Log.d("Thread", "main " + Thread.currentThread().name) }
     .subscribe(
         { result -> Log.d("Thread", "main subscribe " + Thread.currentThread().name)}
         , { error -> {} }
         )
    

결과는 다음과 같습니다.

both, doOnSubscribe C main
both, doOnSubscribe A Thread 2
both, doOnSubscribe B Thread 2

both, doOnNext A Thread 2
both, map A Thread 2

both, doOnNext B Thread 1
both, map B Thread 1

both, doOnNext C Thread 1
both, map C Thread 1

main main
main subscribe main
result: what if use both A B C

바와 같이, '우리'는 '우리'입니다.doOnSubscribe맨 아래부터 맨 위까지., ,, ②, ,, ,,subscribe는 다른 연산자보다 우선도가 높기 때문에 첫 번째 코드를 처리하는 스레드는 스레드2였습니다

그리고 다른 교환원들이 한 줄 한 줄 호출되었습니다.★★★ observeOn레 , , , 、 경 、 경 、 , 、 , 、 , , 。Thread 1subscribe,observeOn스레드를 메인 스레드로 변경하기 위해 다시 호출되었습니다.(Android Scheduler).일종의 스케줄러일 뿐입니다)

TL;DR;

  • 번째 패스인 '''는subscribeOn맨 아래부터 맨 위까지.
  • 번째 경로, " " " " 입니다.observeOn다른 코드와 함께 위에서 아래로 호출됩니다.
  • RxJava2와 RxJava3의 동작은 동일했습니다.

언급URL : https://stackoverflow.com/questions/44984730/rxandroid-whats-the-difference-between-subscribeon-and-observeon

반응형