본문 바로가기

Android/지식저장소

[Android] RxJava2 + Retrofit2 에서 언제 call 이 cancel 되는가 고찰

너무 피곤해서 코드만 보고 의식의 흐름대로 작성해본 것. 주관이 많이 들어갔기때문에 100% 신뢰해서는 안된다.

 

전제 : retrofit 이 리턴해주는 Single 을 옵저버블로 변환해 사용중(우리 프로젝트 구조의 특성상 이렇게 했다)

 

1. Retrofit 은 인터페이스로 정의한 API 를 기반으로, 어노테이션 프로세서를 이용해? 뚝딱뚝딱 어떤 클래스 를 만들어낸다.

// Retrofit.class
// 여기서 T 는 클래스 (Something::class.java)
public <T> T create(final Class<T> service) {
  Utils.validateServiceInterface(service);

  if (validateEagerly) {
    eagerlyValidateMethods(service);
  }

  return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
      new InvocationHandler() {
        private final Platform platform = Platform.get();

        @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
            throws Throwable {
          // If the method is a method from Object then defer to normal invocation.
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          if (platform.isDefaultMethod(method)) {
            return platform.invokeDefaultMethod(method, service, proxy, args);
          }
          ServiceMethod<Object, Object> serviceMethod =
              (ServiceMethod<Object, Object>) loadServiceMethod(method);
          OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
          return serviceMethod.adapt(okHttpCall);
        }
      });
}

 

2. 만들어진 클래스 내부에서 어떤 메서드가 ServiceMethod 객체를 만들고, 이를 OkHttpCall 로 감싼 후 ServiceMethod.adapt(okHttpCall) 를 리턴한다.

 

3. 여기서 호출되는 ServiceMethod.adapt() 메서드는 RxJava2CallAdapter 일거라는 킹리적 갓심이 든다. 

 

4. RxJava2CallAdapter 의 adapt 메서드를 살펴보면 여기서 옵저버블을 만든다.

@Override public Object adapt(Call<R> call) {
  Observable<Response<R>> responseObservable = isAsync
      ? new CallEnqueueObservable<>(call)
      : new CallExecuteObservable<>(call); // 당연히 비동기로 할테니까 여기겠지

  Observable<?> observable;

	// 생략
}

 

 

5. CallExecuteObservable 클래스를 살펴보면 아래쪽에 CallDisposable 정의가 있다.

private static final class CallDisposable implements Disposable {
  private final Call<?> call;
  private volatile boolean disposed;

  CallDisposable(Call<?> call) {
    this.call = call;
  }

  @Override public void dispose() {
    disposed = true;
    call.cancel();
  }

  @Override public boolean isDisposed() {
    return disposed;
  }
}

 

 

6. 해당 옵저버블을 구독 시작하면 아래의 메서드가 불리며 위에 정의된 CallDisposable 로 감싼 후 옵저버에게 전달하는 코드를 볼 수 있다.

@Override protected void subscribeActual(Observer<? super Response<T>> observer) {
  // Since Call is a one-shot type, clone it for each new observer.
  Call<T> call = originalCall.clone();
  CallDisposable disposable = new CallDisposable(call);
  observer.onSubscribe(disposable);

	// 생략
}

 

 

7. 옵저버블이 dispose 되면 당연히 콜이 캔슬될거라는 결론에 도달한다.