Retrofit 2로 HTTP 호출하기

Android Weekly 188에 실린 How to make HTTP calls on Android with Retrofit 2의 번역 글입니다. 작가인 Oleg Šelajev는 개발자이자 작가, 학생이자 강연자로 Java, Clojure, Haskell, JavaScript를 사용하며, Rebellabs를 운영하고 있습니다. Oleg가 소개하는 Retrofit 2 HTTP 클라이언트 사용법을 살펴보세요.


Retrofit 2 소개

Retrofit은 Square가 제공하는 안드로이드와 Java 애플리케이션을 위한 라이브러리로, 안전한 타입(type-safe) 방식의 HTTP 클라이언트입니다. 이번 글에서는 Retrofit 2 HTTP 클라이언트의 사용 복잡성과 앱 적용 시의 유용성을 살펴볼 예정입니다.

안전한 타입 방식의 HTTP 클라이언트이므로 URL 생성이나 매개 변수의 설정 등을 걱정할 필요 없이 네트워크로 보낼 쿼리 문법만 살펴보면 됩니다. Retrofit을 사용하면 몇몇 인터페이스를 작성하는 것으로 이런 작업을 정말 쉽게 할 수 있습니다.

프로젝트 생성

Minimum SDK가 23인 Phone and Tablet용 Blank Activity를 생성합니다.



프로젝트 선택에 자신이 없으시면 Github: Floating button app skeleton에서 소스코드를 받아도 됩니다.

저자 tip: 안드로이드 스튜디오 유료 플러그인 JRebel을 사용하면 실행 중인 기기에서 실시간으로 코드를 업데이트할 수 있습니다.

이제 MainActivity의 floating action button을 누르면 나타나는 snackbar를 바꿔볼까요? JRebel을 사용한다면 파일 저장 후 버튼만 하나 누르는 것으로 바뀐 코드가 바로 적용됩니다.

이런 개발 뉴스를 더 만나보세요

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {

  @Override
  public void onClick(View view) {
    Snackbar.make(view, Super fast hello world, Snackbar.LENGTH_LONG)
      .setAction(Action, null).show();
  }
});

Retrofit 2 추가

build.gradle 파일에 아래와 같이 Retrofit 2를 추가합니다.

compile ‘com.squareup.retrofit2:retrofit:2.0.0-beta2’
compile ‘com.squareup.retrofit2:gson-converter:2.0.0-beta2’

specification 인터페이스 생성

Retrofit은 인터페이스를 사용해서 runtime에 HTTP 서비스 쿼리 코드를 생성할 수 있습니다. 다음과 같은 모델 클래스(contributor.java)를 만든다고 가정해 보겠습니다.

public class Contributor {

    String login;
    String html_url;

    int contributions;

    @Override
    public String toString() {
        return login + " (" + contributions + ")";
    }
}

HTTP 통신을 표현하는 인터페이스를 생성하기 위해 GitHubService라는 클래스를 만들고 다음과 같은 코드를 넣습니다.

public interface GitHubService {
  @GET(repos/{owner}/{repo}/contributors)
  Call<List<Contributor>> repoContributors(
      @Path(owner) String owner,
      @Path(repo) String repo);
}

인터페이스 메서드 위에 @GET 어노테이션을 붙이고 URL의 path를 넣는 것만으로 간단하게 HTTP 통신을 위한 인터페이스를 만들 수 있습니다. @GET, @POST 등 쿼리 매개 변수를 바꿀 수 있습니다.

* @QueryMap — 매개변수의 맵
* @Body — @POST annotation과 사용해서 쿼리의 바디 컨텐트 제공

Retrofit 객체 생성

앞서 만든 인터페이스를 사용하려면 Retrofit 객체를 만들어야 합니다. GitHubService.java 클래스에 다음과 같은 코드를 넣습니다.

interface GitHubService {
    @GET("repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> repoContributors(
            @Path("owner") String owner,
            @Path("repo") String repo);


    public static final Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("https://api.github.com/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();
}

HTTP 호출

GitHubService 인터페이스를 구현하려면 Call 객체를 초기화하고 요청을 실행합니다.

GitHubService gitHubService = GitHubService.retrofit.create(GitHubService.class);
Call<List<Contributor>> call = gitHubService.repoContributors(square, retrofit);
List<Contributor> result = call.execute().body();

비동기적 호출을 원한다면 아래 코드처럼 구현합니다.

call.enqueue(new Callback<List<Contributor>>() {
  @Override
  public void onResponse(Response<List<Contributor>> response, Retrofit retrofit) {
    // handle success
  }

  @Override
  public void onFailure(Throwable t) {
    // handle failure
  }
});

UI 세팅

코드가 보일 UI를 content_main.xml로 준비합니다. 쿼리를 초기화할 버튼과 결과를 출력할 텍스트뷰를 다음과 같이 만듭니다.

<Button
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Fetch"
  android:id="@+id/button"
  android:layout_alignParentBottom="true"
  android:layout_centerHorizontal="true"
  android:layout_marginBottom="151dp" />

<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:textAppearance="?android:attr/textAppearanceLarge"
  android:text=""
  android:id="@+id/textView"
  android:layout_above="@+id/button"
  android:layout_alignParentEnd="true"
  android:layout_alignParentStart="true"
  android:layout_alignParentTop="true"
  android:textIsSelectable="false" />

처음 네트워크 호출을 하는 분이라면 다음처럼 시도할 수 있겠죠.

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    GitHubService gitHubService = GitHubService.retrofit.create(GitHubService.class);
    Call<List<Contributor>> call = gitHubService.repoContributors(square, retrofit);
    String result = call.execute().body().toString();
    TextView textView = (TextView) findViewById(R.id.textView);
    textView.setText(result);
  }
});

하지만 이 코드는 작동하지 않습니다.

리팩토링

안드로이드는 UI 스레드에서 네트워크 호출을 하는 것을 금하므로 리팩토링이 필요합니다. 네트워크 호출을 위한 백그라운드 스레드를 만들어 볼까요?

private class NetworkCall extends AsyncTask<Call, Void, String> {
  @Override
  protected String doInBackground(Call params) {
    try {
      Call<List<Contributor>> call = params[0];
      Response<List<Contributor>> response = call.execute();
      return response.body().toString();
    } catch (IOException e) {
      e.printStackTrace();
    }
    return null;
  }

  @Override
  protected void onPostExecute(String result) {
    final TextView textView = (TextView) findViewById(R.id.textView);
    textView.setText(result);
  }
}

이제 EventListener를 만들어서 버튼을 클릭하면 네트워크 호출을 하도록 합니다.

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
  @Override
  public void onClick(View view) {
    GitHubService gitHubService = GitHubService.retrofit.create(GitHubService.class);
    final Call<List<Contributor>> call = gitHubService.repoContributors("square", "retrofit");
    new NetworkCall().execute(call);
  }
});

완성 화면

Retrofit 2를 사용하여 간단하게 HTTP 통신을 할 수 있는 앱을 완성했습니다. 완성 화면은 다음과 같습니다.


전체 코드는 GitHub에서 볼 수 있으며, 더 자세한 내용은 원문을 참고해주세요.

향후 계획

향후 이 기본 앱을 발전시켜 의존성 주입 프레임워크를 만들어서 UI 코드의 복잡도를 낮추고 네트워크 쿼리를 처리하는 RxAndroid를 적용하고자 합니다. 혹시 좋은 라이브러리를 알고 계시거나 아이디어가 있으신 분은 Twitter: @shelajev로 연락주세요.

컨텐츠에 대하여

이 컨텐츠는 저자의 허가 하에 이곳에서 공유합니다.


Realm Korea

Realm Korea Team

4 design patterns for a RESTless mobile integration »

close