Android에서 Retrofit 사용하기 두번째 포스팅 입니다.

이전 포스팅에서는 Retrofit을 프로젝트에 추가하고 간단히 사용해보이는 포스팅을 작성하였는데요.

Retrofit객체 설정 -> API 규격에 맞는 Interface 선언 -> Retrofit객체와 Interface를 이용한 클라이언트 객체 생성

이러한 일괄의 과정을 통해 결론적으로 얻게 되는 클라이언트 객체를 이용하여 실제 통신을 하게 된다는 것을 이전 포스팅에서 알아보았습니다.

하지만, 아쉽게도 하나의 Application에서는 한번의 통신만이 아닌 수많은 REST API 통신을 구성하여 실제 사용자와 인터렉션한다는 것을 알고 계실 겁니다.

그렇다면 만약 우리가 개발해야 될 App에 50번의 통신이 발생한다고 과정해보죠.

Interface는 단순히 method를 늘려가는 작업으로 해결 될 수 있을 것 같지만,

최악의 경우, 통신이 필요한 곳마다 위에 적혀 있는 일괄의 작업을 50번 하게 됩니다.

그렇다면 더 최악의 경우, Retrofit객체가 50번이나 생성될 수도 있다는 암묵적인 의미도 가지고 있을 수 있겠네요…

그렇다면 여기서 한번 더 시나리오를 추가해봅시다.

  • 특정 상황에 의해 통신해야 될 API 서버의 URL이 바뀌어 버린다면?
  • 서버 개발자와 기존엔 협의 되지 않았던 Header에 Token 정보를 API 요청 시, 전달해달라고 한다면?

지금 당장엔 두가지 밖에 떠오르지 않는군요.

여러분은 이러한 상황을 겪었을 경우, 문제를 해결하기 위해 어떻게 접근하실 건가요?

정말 일차원적인 생각으로는 하나의 Retrofit 객체를 잘 작동하게 변경하여 50번의 ctrl + c / v를 통해 변경하는 방법이 있습니다.

하지만, 제가 생각하는 개발자란 종족은 언제나 게으르고 싶어하는 종족이라고 생각이 됩니다.

같은 작업을 여러번 하기 싫어하기 때문에, 시스템을 통해 자동화를 하기 시작한게 아닐까요?

이렇듯, 게으른 우리 개발자님들을 위해,

갑작스레 어떠한 변수가 생기더라도 조금 더 대응하기 쉽고, 조금 더 사용하기 쉽게 Retrofit을 관리할 수 있는 방법인 ServiceGenerator클래스에 대해 포스팅을 해보려 합니다.

솔직히, 이번 포스팅은 특별히 적어나갈 내용이 없어요…ㅜㅜㅜ

그럼에도 불구하고 이러한 내용을 정리하는 목적요?

설마 서버 URL이 그렇게 자주 바뀌겠어?와 같은 변명을 해보고 싶지만, 제가 위에 잠시 언급했던 일차원적인 삽질을 하던 개발자 였거든요…ㅎㅎ

하지만 일차원적이였던 저도 어느 순간 개선을 위해 발버둥을 하였고, 나름대로 Retrofit을 관리하는 별도의 클래스를 작성했던 적이 있는데,

우연히 Retrofit에 대한 정보를 얻기 위해 구글링 중, FutureStudio BlogServiceGenerator클래스를 접한적이 있었습니다.

이 클래스를 보고 나서, 우와, 내가 작성했던 클래스가 틀린 방법은 아니였구나!라는 생각과 나름 개인적인 뿌듯함을 느꼈던 적이 있었습니다.

물론, FutrueStudio Blog를 제가 Retrofit을 갓 사용하게 되었을 때 알았더라면 더 좋긴 했겠지만요…
왜냐하면, 코드는 제가 작성한 클래스보다 ServiceGenerator가 더 이쁘거든요…ㅜㅜ

그래서, 혹시라도 저와 같은 삽질을 경험하고 계시는 분이 남아 계시다면 더 좋은 방법과 코드를 위해 소개를 해드리고자 포스팅을 쓰게 되었습니다.

시작하기에 앞서

앞으로 계속적으로 Retrofit과 관련된 포스팅을 추가해 나갈 예정 이기에,

혹시 이전의 글을 참고하시고 싶은 분들을 위해 항상 글의 서두에는 이미 작성된 포스팅을 연관 포스팅 섹션으로 소개하고 시작하고자 합니다.

또한, 각 포스팅 마다 관련된 예제 코드의 전체 소스를 확인할 수 있도록 관련된 Github Repository를 언급하고 시작할까 합니다.

연관 포스팅

ServiceGenerator Class 작성.

지금 작성하려는 이 ServiceGenerator라는 녀석은 도대체 뭘 위해서 작성하는 걸까요?

위에서도 잠시 언급했지만, 궁극적인 목적은 공통적으로 사용될 코드의 분리 라고 생각합니다.

더불어 유지보수의 편리성을 위해서 이겠지요.

특별한 경우가 아니라면 하나의 Application은 하나의 동일한 서버로 요청을 하고, 사용자 인증에 관련된 정보 또한 서버 개발자와 협의된 방식을 이용하여 동일한 방법으로 요청을 하게 됩니다.

그렇기에 통신을 필요로하는 곳 마다 Retrofit 객체를 생성할 필요는 없습니다.

하나의 Retrofit 객체만 생성하여 관리하고, 생성된 해당 Retrofit 객체를 이용하여 사용될 Interface만 교체해가며, 클라이언트 객체를 만들어내기만 하면 되니까요.

백문이 불여일타 코드부터 확인해봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class ServiceGenerator {
private static final String URL = "https://api.github.com/";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(URL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build());
private static Retrofit retrofit = builder.build();
public static <S> S createService(Class<S> serviceClass) {
return retrofit.create(serviceClass);
}
}

이미 이전 포스팅에서 Retrofit.Builder의 설정 및 Retrofit 객체 생성에 대해서는 다루었던 부분이기에, 이해가 안가시는 코드는 없을 것으로 판단됩니다.

정말 기본적인 설정만을 가지고 만들어진 ServiceGenerator의 골격입니다.

이전 포스팅인 Retrofit 기본 사용법에서 살펴 보았듯, URL을 설정하고 사용할 Converter를 지정해주는 코드를 별도의 클래스로 분리한 것이죠.

static 키워드를 이용하여 해당 Retrofit 객체를 정적 객체로 만들어 주었다는 것 밖에는 없습니다.

한가지 조금 틀린점이 있다면 createService()라는 정적 method가 추가되었다는 것인데요.

API 명세에 따라 용도에 맞게 Interface를 여러개 생성할 수 있기 때문에 Generic 타입으로 Interface Class를 매개변수로 받을 수 있도록 해주었고,

받아온 Interface 타입으로 클라이언트 객체를 리턴해주기 위해 Generic 타입을 그대로 다시 리턴해주는 역할을 합니다.

ServiceGenerator Class 사용.

그렇다면, 이제 이렇게 작성된 ServiceGenerator를 실제 사용하는 법을 알아봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GithubService service = ServiceGenerator.createService(GithubService.class);
Call<JsonArray> request = service.getUserRepositories("dev-juyoung");
request.enqueue(new Callback<JsonArray>() {
@Override
public void onResponse(Call<JsonArray> call, Response<JsonArray> response) {
// Code...
}
@Override
public void onFailure(Call<JsonArray> call, Throwable t) {
// Code...
}
});

통신이 필요한 곳에서 Retrofit 객체를 생성해주고, 생성된 Retrofit 객체와 Interface를 이용하여 클라이언트 객체를 만드는 몇줄에 걸쳐 작성되어야 할 코드들 대신,

우리가 작성한 ServiceGenerator 클래스를 이용하고, 해당 클래스에 정의되어 있는 createService() method를 호출하여, 클라이언트 객체를 가져오기만 하면 됩니다.

클라이언트 객체를 가져온 이후부터는 지금까지와 같은 방식으로 enqueue() 또는 execute()를 이용해 실제 통신을 진행하시면 되죠.

Square에서 Retrofit 사용을 워낙 간단하게 할 수 있도록 만들어 주었기에 몇 줄 차이나진 않지만, 그래도 조금은 깔끔해진 느낌이 들지 않나요?

마무리.

이번 포스팅에서는 ServiceGenerator라는 녀석으로 Retrofit에 대한 설정과 객체생성, 그리고 실제 통신에 사용될 클라이언트 객체에 대한 생성과 관련된 부분을 별도의 클래스로 분리하는 방법을 소개해드렸습니다.

글을 작성하며, 이 글을 따로 분리 할 필요가 있을까?라는 의문도 조금은 들긴 했습니다.

어떤분에게는 당연히 이렇게 분리해서 설계하는게 맞지 않아? 라는 반응이 있을 수도,

어떤분에게는 특별히 개선된 걸 잘 모르겠는데?라는 반응이 있을 수도 있습니다.

하지만 실질적으로 많은 분들과 이야기를 나눠보면 저와 같은 초보개발자 분들은 ctrl + c / v 불상사를 겪었던 분들이 적진 않은 것으로 보입니다.

물론 조금 더 고민하고 시간을 두고 프로그램을 작성한다면 나중에 있을 변수와 유지보수까지 고려한 코드를 작성할 순 있겠지만,

스타트업과 같은 환경에서는 시간에 쫓겨 작성하다 보면 저처럼, 이러한 사소한 부분을 놓치는 바람에 후에 큰 불상사를 겪기도 하지요.

여하튼, 저도 시간에 쫓긴다고 급하게 작성할 게 아니라 이렇게 공통적으로 사용이 가능한 코드는 ServiceGenerator와 같은 클래스처럼 별도로 분리해서 작성하는 버릇을 조금 들여야 한다고 이번 글을 작성하며 다시 한번 반성하게 되었습니다.

그리고 더 나아가, 누구에겐 아무것도 아닐 수 있겠지만 이러한 습관을 들이는 것이 Java의 핵심인 OOP에 조금 더 가까워 질 수 있는 방법이 아닐까 싶기도 하구요.

각설하고, 이번 포스팅에서는 어찌보면 제 신세한탄인가 싶을 정도의 포스팅이 되었지만, 궁극적인 주제는 ServiceGenerator였습니다!

혹여 아직도, Retrofit에 대한 설정과 사용을 ctrl + c/v로 처리하고 계신가요?

그렇다면 소개해드린 ServiceGenerator 클래스를 작성하여 코드를 개선해 보세요!
물론 기존 코드들 정리해야 되는 시간이 소요된다는 건 안 비밀…

약간의 시간이 소요되더라도 조금의 노력으로 조금 더 나은 프로그래밍을 할 수 있다면 더 좋은게 아닐까요? ㅎㅎ

이번 포스팅(신세한탄)은 이쯤에서 마무리하고, 두번의 간단한 Retrofit 소개가 있었으니, 실제 사용에 대한 감도 익히셔야 겠죠?

다음 포스팅에서는 Retrofit과는 조금 주제에 거리감이 있을 수 있지만,

지금까지 다룬 Retrofit과 포스팅으로 다루진 않았지만, Android에서 리스트를 표출하기 위한 RecyclerView를 이용하여 일반적인 Android 개발에 사용되는 MVC Pattern을 적용한 통신과 리스트 표출에 대한 내용을 다뤄보고자 합니다.

이번 글에서도 잘못된 정보가 있다면, 댓글에 거침없는 질타와 조언 부탁드립니다! 끝까지 읽어주셔서 감사합니다.