Retrofit을 사용하면서 suspend를 사용하면 따로 비동기 처리하지 않고 ViewModel에서 viewModelScope사용해도 무방했다
그래서 왜 이렇게 사용할 수 있는지 궁금했고 이러한 궁금증을 풀기 위해 Retorit을 내부코드를 살펴보았다
먼저 Retrofit create()를 살펴보았다.
validateServiceInterface() 메서드를 실행하고 있다
validateServiceInterface() 메서드 내부를 살펴보니 전달받은 인터페이스 여부를 판단하고 아니라면 IllegalArgumentException이 발생한다
다시 create() 메서드를 살펴보면 인터페이스 여부를 확인하고 리턴하게 되는데 이때 Proxy를 이용해서 invoke를 수행하고 있다.
그런데 왜 사용하는 거지?
아마도 네트워크 통신 과정에서 민감한 정보들이 오고 가기 때문에 프록시를 사용하는 것으로 추측된다.
하지만 코드를 살펴보면, 단순한 프록시 패턴이 아니라 Dynamic Proxy 패턴을 사용했다.
그 이유는 기능을 추가할 때 코드 중복이 발생할 수 있는데, 이러한 단점을 보완하기 위해서 Dynamic Proxy를 사용한다고 한다.
ServiceMethod.parseAnnotations()를 통해 어노테이션을 파싱되는 것을 추측 해볼 수 있다 그래서 따라가보면 다음과 같은 코드를 보여준다.
RequestFactory.parseAnnotations를 통해 어노테이션을 정규식을 통해 파싱하고 하고 그에 대한 정보를 requestFactory에 담는다. 그리고 그것을 retrofit 객체, method 정보와 함께 리턴한다. 따라서 어노테이션을 파싱하는 함수를 통해 @Get, @Post 등과 같은 어노테이션을 사용할 수 있다
HttpServiceMethod의 코드를 보니 코틀린 suspend 함수사용 여부를 판단하는 코드가 있다.
suspend function이 아니라면 CallAdapted를 생성하여 리턴하고, Response 객체를 리턴값으로 가진다면 SuspendForResponse를, Body가 필요하다면 SuspendForBody를 생성하여 리턴해준다.
SuspendForBody를 따라 가보면 awaitResponse를 확인할 수 있다. 이것의 코드를 살펴보면 다음과 같다
코드를 보면 enqueue를 통해서 비동기 처리를 하고 있다는 것을 알 수 있다
따라서 내부에서 enqueue를 이미 진행하고 있기 때문에 별도로 비동기 처리하지 않아도 된다.
viewModelScope.launch {
...
}
그래서 나 같은 경우에 ViewModel에서 viewModelScope 즉 메인스레드만 처리해도 된다.
Retrofit은 내부적으로 enqueue 메소드를 구현하여 별도의 백그라운드 스레드를 사용하지 않고도 비동기 처리를 지원한다. 또한, Dynamic Proxy를 사용함으로써 네트워크 통신 중에 민감한 정보를 안전하게 보호할 수 있으며, 런타임에 코드 실행을 가능하게 한다. 이는 어노테이션을 통해 정의된 내용을 파싱하여 해당 구현체를 동적으로 실행할 수 있게 해준다.