[안드로이드 오픈소스 프레임워크 인터뷰 질문] RxJava 프레임워크의 스레드 스위칭 원리, RxJava1과 RxJava2의 차이점은 무엇인가요?

RxJava 프레임워크의 스레드 전환 원리, RxJava1과 RxJava2의 차이점은 무엇입니까?

이 질문에서 무엇을 조사하고 싶습니까?

인기 있는 프레임워크인 RxJava를 숙지하세요. RxJava 스레드 전환을 유연하게 사용하여 복잡한 애플리케이션 시나리오를 구현할 수 있습니까?

조사할 지식 포인트
  1. RxJava 원칙
  2. 핸들러 스레드 전환
지원자는 어떻게 대답해야 할까?
스레드 전환
observable.subscribeOn(Schedulers.io())
     .observeOn(AndroidSchedulers.mainThread())
     .subscribe(observer);

RxJava 스위칭 스레드는 subscribeOn()과observOn()의 두 부분으로 나뉩니다.

구독온()

먼저 subscribeOn()의 소스코드는 다음과 같습니다.

public final Observable<T> subscribeOn(Scheduler scheduler) {
    
    
  ObjectHelper.requireNonNull(scheduler, "scheduler is null");
  return RxJavaPlugins.onAssembly(new ObservableSubscribeOn<T>(this, scheduler));
}

Scheduler 클래스를 전달했는데, Scheduler는 지연되거나 주기적으로 작업을 실행할 수 있는 예약 클래스입니다.

스케줄러에는 다음과 같은 유형이 있습니다.

유형 용법 의미 사용되는 장면
IoScheduler Schedulers.io() io 작업 스레드 SD 카드 파일 읽기 및 쓰기, 데이터베이스 쿼리, 네트워크 액세스 및 기타 IO 집약적인 작업
NewThread스케줄러 Schedulers.newThread() 새 스레드 만들기 시간이 많이 걸리는 작업 등
단일 스케줄러 Schedulers.single() 싱글톤 스레드 싱글톤 스레드가 하나만 필요한 경우
계산스케줄러 스케줄러.계산() CPU 컴퓨팅 작업 스레드 이미지 압축 샘플링, xml, json 구문 분석 및 기타 CPU 집약적인 계산
트램펄린스케줄러 Schedulers.trampoline() 현재 스레드 현재 스레드에서 작업을 즉시 실행해야 하는 경우
핸들러스케줄러 AndroidSchedulers.mainThread() 안드로이드 메인 스레드 UI 등 업데이트

그러면 더 이상 아무것도 없습니다. 단지 ObservableSubscribeOn 객체를 반환하는 것뿐입니다.

관찰온()

먼저 소스코드를 살펴보면 다음과 같습니다.

public final Observable<T> observeOn(Scheduler scheduler) {
    
    
  return observeOn(scheduler, false, bufferSize());
}
 
public final Observable<T> observeOn(Scheduler scheduler, boolean delayError, int bufferSize) {
    
    
  ObjectHelper.requireNonNull(scheduler, "scheduler is null");
  ObjectHelper.verifyPositive(bufferSize, "bufferSize");
  return RxJavaPlugins.onAssembly(new ObservableObserveOn<T>(this, scheduler, delayError, bufferSize));
}

여기에는 아무것도 없으며, 결국 ObservableObserveOn 객체를 반환합니다.

그런 다음 이전과 같이 subscribe() 메서드를 호출하여 구독합니다. 전체적인 변화는 크지 않고 일부 객체를 캡슐화하는 것 같지만 이것이 RxJava 소스 코드의 핵심입니다. 다시 subscribeActual() 메서드를 호출하면 ObservableCreate()의 subscribeActual 메소드 대신 ObservableObserveOn의 subscribeActual() 메소드가 먼저 호출되며 해당 소스코드는 다음과 같습니다.

protected void subscribeActual(Observer<? super T> observer) {
    
    
  if (scheduler instanceof TrampolineScheduler) {
    
    
    source.subscribe(observer);
  } else {
    
    
    Scheduler.Worker w = scheduler.createWorker();
    source.subscribe(new ObserveOnObserver<T>(observer, w, delayError, bufferSize));
  }
}

여기서 이야기할 점은 두 가지인데, 하나는 ObserveOnObserver가 나중에 자세히 설명할 옵저버를 실행하는 스레드이고, 그 다음이 source.subscribe라는 점입니다. 이 source.subscribe는 ObservableSubscribeOn의 subscribe 메소드를 호출하고, subscribe 메소드는 Observable도 상속하는데 Observable의 메소드이므로 위의 ObservableCreate와 동일한 메소드이므로 ObservableSubscribeOn의 subscribeActual() 메소드가 호출되며 해당 코드는 다음과 같습니다.

public void subscribeActual(final Observer<? super T> s) {
    
    
  final SubscribeOnObserver<T> parent = new SubscribeOnObserver<T>(s);
  s.onSubscribe(parent);
  parent.setDisposable(scheduler.scheduleDirect(new SubscribeTask(parent)));
}

위 코드에서는 먼저 ObserveOnObserver가 SubscribeOnObserver로 반환하는 것을 "패키지"한 다음 템플릿 코드에 해당하는 onSubscribe() 메서드인 Observer의 onSubscribe()를 콜백합니다.

다음으로 SubscribeTask 클래스의 소스 코드를 살펴보세요.

final class SubscribeTask implements Runnable {
    
    
  private final SubscribeOnObserver<T> parent;
  SubscribeTask(SubscribeOnObserver<T> parent) {
    
    
    this.parent = parent;
  }
  @Override
  public void run() {
    
    
    source.subscribe(parent);
  }
}

그 중 source.subscribe(parent)는 자식 스레드를 실행하기 위한 콜백 메소드로, 우리 템플릿 코드의 옵저버의 subscribe() 메소드에 해당합니다. run() 메소드에 위치하며 Runnable을 상속합니다. 이는 이 클래스가 주로 스레드에 의해 실행됨을 나타냅니다. 그런 다음 다음과 같이 Scheduler.scheduleDirect() 메서드에 해당하는 소스 코드를 살펴보세요.

public Disposable scheduleDirect(@NonNull Runnable run) {
    
    
  return scheduleDirect(run, 0L, TimeUnit.NANOSECONDS);
}
 
public Disposable scheduleDirect(@NonNull Runnable run, long delay, @NonNull TimeUnit unit) {
    
    
  final Worker w = createWorker();
  final Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
  DisposeTask task = new DisposeTask(decoratedRun, w);
  w.schedule(task, delay, unit);
  return task;
}

여기서 createWorker()도 추상 메소드입니다. 이는 스케줄링 클래스에 해당하는 Schedulers 클래스의 메소드를 호출합니다. 다음은 IoScheduler 클래스입니다.

public final class IoScheduler extends Scheduler{
    
    
 
  final AtomicReference<CachedWorkerPool> pool;
 
  //省略....
 
  public Worker createWorker() {
    
    
    return new EventLoopWorker(pool.get());
  }
 
  static final class EventLoopWorker extends Scheduler.Worker {
    
    
    private final CompositeDisposable tasks;
    private final CachedWorkerPool pool;
    private final ThreadWorker threadWorker;
 
    final AtomicBoolean once = new AtomicBoolean();
 
    EventLoopWorker(CachedWorkerPool pool) {
    
    
      this.pool = pool;
      this.tasks = new CompositeDisposable();
      this.threadWorker = pool.get();
    }
 
    //省略....
 
    @NonNull
    @Override
    public Disposable schedule(@NonNull Runnable action, long delayTime, @NonNull TimeUnit unit) {
    
    
      if (tasks.isDisposed()) {
    
    
        // don't schedule, we are unsubscribed
        return EmptyDisposable.INSTANCE;
      }
      return threadWorker.scheduleActual(action, delayTime, unit, tasks);
    }
  }
 
}
 
 static final class CachedWorkerPool implements Runnable {
    
    
 
  //省略....
 
  ThreadWorker get() {
    
    
    if (allWorkers.isDisposed()) {
    
    
      return SHUTDOWN_THREAD_WORKER;
    }
    while (!expiringWorkerQueue.isEmpty()) {
    
    
      ThreadWorker threadWorker = expiringWorkerQueue.poll();
      if (threadWorker != null) {
    
    
        return threadWorker;
      }
    }
 
    ThreadWorker w = new ThreadWorker(threadFactory);
    allWorkers.add(w);
    return w;
   }
   //省略....
}

이것이 IoScheduler의 createWorker() 메소드인데, 사실 주된 의미는 SubscribeTask()가 실행될 수 있도록 자식 스레드를 생성할 수 있도록 스레드 풀을 얻는 것입니다. 그런 다음 w.schedule(task, 지연, 단위) 메서드를 직접 호출하여 스레드 풀에서 실행되도록 합니다. 위 ThreadWorker의 소스코드는 다음과 같습니다.

static final class ThreadWorker extends NewThreadWorker {
    
    
  private long expirationTime;
  ThreadWorker(ThreadFactory threadFactory) {
    
    
    super(threadFactory);
    this.expirationTime = 0L;
  }
 
  //省略代码....
 }
 
public class NewThreadWorker extends Scheduler.Worker implements Disposable {
    
    
  private final ScheduledExecutorService executor;
 
  public NewThreadWorker(ThreadFactory threadFactory) {
    
    
    executor = SchedulerPoolFactory.create(threadFactory);
  }
 
  public ScheduledRunnable scheduleActual(final Runnable run, long delayTime, @NonNull TimeUnit unit, @Nullable DisposableContainer parent) {
    
    
    Runnable decoratedRun = RxJavaPlugins.onSchedule(run);
 
    ScheduledRunnable sr = new ScheduledRunnable(decoratedRun, parent);
 
    if (parent != null) {
    
    
      if (!parent.add(sr)) {
    
    
        return sr;
      }
    }
 
    Future<?> f;
    try {
    
    
      if (delayTime <= 0) {
    
    
        f = executor.submit((Callable<Object>)sr);
      } else {
    
    
        f = executor.schedule((Callable<Object>)sr, delayTime, unit);
      }
      sr.setFuture(f);
    } catch (RejectedExecutionException ex) {
    
    
      if (parent != null) {
    
    
        parent.remove(sr);
      }
      RxJavaPlugins.onError(ex);
    }
 
    return sr;
  }
}

보시다시피 이는 원래 Java API를 조정하여 스레드 풀 작업을 수행합니다.

그런 다음 마지막 단계는 하위 스레드에서 source.subscribe(parent) 메서드를 호출한 다음 방금 생성된 ObservableCreate의 subscribeActual()을 다시 호출하는 것입니다.

protected void subscribeActual(Observer<? super T> observer) {
    
    
    CreateEmitter<T> parent = new CreateEmitter<T>(observer);
    observer.onSubscribe(parent);
    try {
    
    
      source.subscribe(parent);
    } catch (Throwable ex) {
    
    
      Exceptions.throwIfFatal(ex);
      parent.onError(ex);
    }
}

메시지 구독 바인딩을 수행합니다.

Emitter.onNext(content)를 호출하면 io 스레드에 있습니다. 콜백 onNext()는 언제 전환됩니까? 즉, 전체 프로세스의 원활한 진행을 위해 앞서 언급하지 않았던observeOn()의 ObserveOnObserver는 관찰자의 스레드를 실행하는 프로세스이다.

class ObserveOnObserver<T> extends BasicIntQueueDisposable<T>
  implements Observer<T>, Runnable {
    
    
 
    //省略代码....
 
    ObserveOnObserver(Observer<? super T> actual, Scheduler.Worker worker, boolean delayError, int bufferSize) {
    
    
      this.actual = actual;
      this.worker = worker;
      this.delayError = delayError;
      this.bufferSize = bufferSize;
    }
 
    @Override
    public void onSubscribe(Disposable s) {
    
    
      if (DisposableHelper.validate(this.s, s)) {
    
    
        this.s = s;
        if (s instanceof QueueDisposable) {
    
    
          @SuppressWarnings("unchecked")
          QueueDisposable<T> qd = (QueueDisposable<T>) s;
          int m = qd.requestFusion(QueueDisposable.ANY | QueueDisposable.BOUNDARY);
          if (m == QueueDisposable.SYNC) {
    
    
            sourceMode = m;
            queue = qd;
            done = true;
            actual.onSubscribe(this);
            schedule();
            return;
          }
          if (m == QueueDisposable.ASYNC) {
    
    
            sourceMode = m;
            queue = qd;
            actual.onSubscribe(this);
            return;
          }
        }
        queue = new SpscLinkedArrayQueue<T>(bufferSize);
        actual.onSubscribe(this);
      }
    }
 
    @Override
    public void onNext(T t) {
    
    
      if (done) {
    
    
        return;
      }
      if (sourceMode != QueueDisposable.ASYNC) {
    
    
        queue.offer(t);
      }
      schedule();
    }  
 
    void schedule() {
    
    
      if (getAndIncrement() == 0) {
    
    
        worker.schedule(this);
      }
    }
    //省略代码....
  }

Emitter.onNext(content) 메소드가 호출되면 위의 onNext() 메소드가 호출되고, 이 메소드에서 데이터가 큐에 푸시된 후 작업자.schedule(this) 메소드가 실행됩니다. 작업이란 무엇인가요? AndroidSchedulers .mainThread()를 기억하시나요? 이는 HandlerScheduler 클래스에 해당하므로 createWorker()는 다음에 해당합니다.

private static final class MainHolder {
    
    
    static final Scheduler DEFAULT = new HandlerScheduler(new Handler(Looper.getMainLooper()));
}
 
 
public Worker createWorker() {
    
    
  return new HandlerWorker(handler);
}
 
private static final class HandlerWorker extends Worker {
    
    
    private final Handler handler;
    private volatile boolean disposed;
 
    HandlerWorker(Handler handler) {
    
    
      this.handler = handler;
    }
 
    @Override
    public Disposable schedule(Runnable run, long delay, TimeUnit unit) {
    
    
      if (run == null) throw new NullPointerException("run == null");
      if (unit == null) throw new NullPointerException("unit == null");
      if (disposed) {
    
    
        return Disposables.disposed();
      }
      run = RxJavaPlugins.onSchedule(run);
      ScheduledRunnable scheduled = new ScheduledRunnable(handler, run);
      Message message = Message.obtain(handler, scheduled);
      message.obj = this; // Used as token for batch disposal of this worker's runnables.
      handler.sendMessageDelayed(message, unit.toMillis(delay));
      if (disposed) {
    
    
        handler.removeCallbacks(scheduled);
        return Disposables.disposed();
      }
      return scheduled;
    }
}

next() 메서드에서는 Android에 포함된 Handler 메시지 메커니즘을 사용하여 Message에 메서드를 래핑하고 handler.sendMessageDelayed()를 통해 메시지를 전송하면 Next() 메서드가 UI 스레드에서 다시 호출되어 다음을 실현합니다. 서브루틴 스레드가 Android의 메인 스레드로 전환됩니다. 메인 스레드에서 데이터를 얻은 후에는 메인 스레드에서 다양한 작업을 수행할 수 있습니다.

RxJava1과 RxJava2의 차이점
  1. RxJava 2.0은 더 이상 null 값을 지원하지 않습니다.

    Observable.just(null);
    Single.just(null);
    Flowable.just(null);
    
  2. RxJava 2.0의 모든 함수 인터페이스(Function/Action/Consumer)는 변환이 필요한 컴파일 예외 문제를 해결하기 위해 예외를 발생시키도록 설계되었습니다.

  3. RxJava 1.0의 Observable은 BackPressure를 잘 지원하지 못하는데, RxJava2.0에서는 Observable을 완벽하게 구현하여 BackPressure를 지원하지 않고 Flowable을 추가하여 BackPressure를 지원합니다.

역압력은 비동기식 시나리오에서 관찰자가 처리할 수 있는 것보다 훨씬 빠르게 이벤트를 전송하여 다운스트림 버퍼가 오버플로되는 것을 의미합니다.

마침내

안드로이드 인터뷰 질문을 모아봤습니다.위의 인터뷰 질문 외에도 [ 자바 기본, 컬렉션, 멀티스레딩, 가상 머신, 리플렉션, 제네릭, 동시 프로그래밍, 안드로이드의 4대 구성 요소, 비동기 작업 및 메시지] 도 포함되어 있습니다. 메커니즘, UI 드로잉, 성능 튜닝, SDN, 타사 프레임워크, 디자인 패턴, Kotlin, 컴퓨터 네트워크, 시스템 시작 프로세스, Dart, Flutter, 알고리즘 및 데이터 구조, NDK, H.264, H.265 오디오 코덱, FFmpeg , OpenMax, OpenCV, OpenGL ES ]
여기에 이미지 설명을 삽입하세요.

도움이 필요한 친구들은 아래 QR 코드를 스캔하여 모든 면접 질문 + 답변 분석을 무료로 받을 수 있습니다! ! !

Guess you like

Origin blog.csdn.net/datian1234/article/details/135157824