Retrofit2에 대해 알아보자! | Android Study

hoya·2021년 8월 16일
4

Android Study

목록 보기
7/19
post-thumbnail

🙄 Retrofit?

안드로이드와 서버간의 REST API 통신을 도와주는 라이브러리로, OkHTTP에 기반을 두고 있으며 현재 가장 널리 쓰이는 통신 라이브러리이다.

Volley, AsyncTask 와 같은 여러 통신 라이브러리가 있는데 Retrofit 이 사랑받는 이유는 무엇일까?


👍 장점


1. 높은 성능

아래의 표를 보자.

🎃 힘의 차이가 느껴지십니까?

한 눈에 보아도 Retrofit 이 위의 두 항목보다 빠른 성능을 자랑하고 있는 모습을 확인할 수 있다.

2. 뛰어난 가독성

Annotation으로 HTTP 메소드를 정의함으로서 코드의 구현이 쉬워지며 개발자들은 행위를 손쉽게 알아볼 수 있게 되어 직관적으로 코드를 설계할 수 있게 된다.

3. 쉬운 유지보수

Retrofit은 서버 연동 시 주로 주고받는 데이터인 JSON, XML을 자동을 파싱해주는 Converter 연동을 지원해주기 때문에, 개발자 입장에서는 유지보수가 매우 편리할 수 밖에 없다.


이렇게 보았을 때, 현재 시중에 있는 통신 라이브러리에서 Retrofit을 사용하지 않을 이유가 없다. 성능도 뛰어나고, 코드 작성도 편리하고, 유지보수도 쉬운데 마다할 이유가 어디 있을까?


🙃 실습


📌 1. 기본 설정

1-1. 의존성 부여

    implementation 'com.squareup.retrofit2:retrofit:2.5.0'-
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'

converter-gson - JSON 타입의 결과를 객체로 자동 매핑(파싱)해주는 아주 기특한 녀석이다.

1-2. 퍼미션 부여

<uses-permission android:name="android.permission.INTERNET" /> <!-- 인터넷 권한 선언 -->

네트워크 통신에 인터넷 권한 선언은 기본적으로 필수이다.


📌 2. 모델 생성

Model 은 서버 연동을 위해 사용하는 데이터 추상화 클래스이다. 위에서 이야기했던 convertor가 JSON 데이터를 자동으로 파싱하고, 객체를 생성한 후 모델에서 정의한 변수에 데이터를 담아준다. 보통 DTO 클래스라고 부른다.

응답 데이터 구조에 맞게 모델 클래스를 선언하면 된다. 간단한 예시로, 사용자가 즐겨찾는 장소를 저장해놓은 API를 선정하였다.

/*
    API 응답 데이터 구조

    [{"success":true,"id":"hoyaho","latitude":37.5024853,"longitude":126.8675475,"title":"favorite 1","content":"content 1"},
    {"success":true,"id":"hoyaho","latitude":37.446536,"longitude":126.640313,"title":"favorite 2","content":"content 2"},
    {"success":true,"id":"hoyaho","latitude":37.462619,"longitude":126.659094,"title":"favorite 3","content":"content 3"},
    {"success":true,"id":"hoyaho","latitude":37.457564,"longitude":126.607801,"title":"favorite 4","content":"content 4"}]
 
 */

public class Favorite {
    @SerializedName("success") // 변수명이 일치할 때는 사용하지 않아도 상관 없음.
    private boolean success;
    private String id; 
    @SerializedName("latitude")
    private double latitude;
    @SerializedName("longitude")
    private double longitude;
    @SerializedName("title")
    private String title;
    @SerializedName("content")
    private String content;

    public Favorite(int fnum, String id, double latitude, double longitude, String title, String content) {
        this.id = id;
        this.latitude = latitude;
        this.longitude = longitude;
        this.title = title;
        this.content = content;
    }
    
    @Override
    public String toString() {
        return "Favorite{" +
                "success=" + success +
                ", id='" + id + '\'' +
                ", latitude=" + latitude +
                ", longitude=" + longitude +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                '}';
    }
}

2-1 모델 생성에 어려움을 겪는다면?

jsonschema2pojo 의 도움을 받으면 매우 간편해진다. JSON 데이터를 자바 클래스로 변환해주는 사이트로, 응답받는 JSON 데이터를 복사해서 그대로 붙여넣기 하면 자동으로 모델을 완성시켜준다.

이렇게 응답 데이터의 결과값을 복사해서 그대로 붙여넣기만 해주면?

🤗 5초만에 모델이 완성된 모습을 확인할 수 있다.


📌 3. 서비스 인터페이스 정의

Retrofit 의 핵심이라고 할 수 있는 부분이다. 해당 함수에서 annotation 으로 HTTP Method 를 지정하고, 서버에 전송할 데이터를 추가하면 그 정보에 맞게 서버를 연동할 수 있는 Call 객체를 자동으로 생성하는 구조이다.

즉, 어떤 형태로 어떻게 통신을 할건지 개발자가 지정만 해주면 Retrofit 이 알아서 구현해준다는 의미이다. 참고로 Service 는 Retrofit 에서 사용하는 용어로, API를 정의하는 인터페이스를 의미한다.

public interface FavoriteService {

    String FAVORITE_URL = "YOUR_URL"; // URL

    // 일반적인 GET방식 서버 호출
    @GET("favorite.php") // HTTP Method, baseUrl 뒤의 경로 지정
    Call<List<Favorite>> getFavorite(
            @Query("id") String id
            // @Query :  url에 쿼리 파라미터 추가 
    );
    
    // URL : https://YOUR_URL/favorite.php?id=hoyaho
    
    // URL의 일부분이 동적 데이터에 의해 결정될 때
    @GET("{group}/favorite.php") 
    Call<List<Favorite>> getFavorite(
            @Path("group") String group,
            // @Path : url의 경로를 동적 할당
            @Query("id") String id
    );
    
    // URL : https://YOUR_URL/group/favorite.php?id=hoyaho

    @FormUrlEncoded 
    // @POST annotation 에서만 사용 가능, 
    // @Field annotation 이 추가된 데이터를 인코딩하여 전송하는 역할 수행
    @POST("favorite.php")
    Call<CheckSuccess> insertFavorite(
            @Field("id") String id, // key, value 형식으로 데이터를 전달
            @Field("latitude") double latitude,
            @Field("longitude") double longitude,
            @Field("title") String title,
            @Field("content") String content
            // @Field annotation 은 개별 매개 변수를 전송하고자 할 때 이용한다.
    );
    
    // URL : https://YOUR_URL/favorite.php
    // 서버 전송 데이터 : id="hoyaho"&latitude=37.5024853&longitdue= . . .

    @POST("favorite.php")
    Call<CheckSuccess> insertFavorite(
    	    @Body Userinfo userinfo // 객체를 JSON 형식으로 전송할 때 사용
            /* 
            @Body annotaiton 역시 POST에서만 사용이 가능하다.
            객체 변수에 값이 지정되어 있지 않다면, 해당 데이터는 전송되지 않는다.
            그러나 기본 데이터 타입은 default 값이 대입되므로 제외된다. 
            */
    );
    
    // URL : https://YOUR_URL/favorite.php
    // 서버 전송 데이터 : {"id":"hoyaho","latitude":37.5024853, "longitude": . . .}

    @DELETE("favorite.php") // @Delete Annotation
    Call<CheckSuccess> deleteFavorite(
            @Query("id") String id
    );
    
    // URL : https://YOUR_URL/favorite.php?id=hoyaho
}

예시만 보아도 손쉽게 REST API 통신이 구현되는 것을 확인할 수 있을 것이다. @Field 와 @Body 의 차이점도 간략하게나마 알아두고 가면 후에 도움이 될 것이다. 각 annotation 의 역할에 대해서는 이 후 자세하게 포스팅하도록 하고, 우선 인터페이스 부분은 넘어가도록 하자.


📌 4. Retrofit 객체 생성

이제 준비는 모두 끝났다. 실제 액티비티에서 Retrofit 객체를 사용하기만 하면 된다.

public void getFavorite() { //

    Gson gson = new GsonBuilder().setLenient().create();
    /*
    통신 시 JSON 사용과 해당 객체의 파싱을 위해 생성
    개인적으로 <List><객체>> 부분을 불러올 때 이 부분이 없으면
    IllegalArgumentException 이 발생하는 것으로 판단됨.
    */

    // Retrofit 생성
    Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(FavoriteService.FAVORITE_URL) // 기본으로 적용되는 서버 URL (반드시 / 로 마무리되게 설정)
        .addConverterFactory(GsonConverterFactory.create(gson)) // JSON 데이터를 Gson 라이브러리로 파싱하고 데이터를 Model에 자동으로 담는 converter
        .build();

    FavoriteService retrofitAPI = retrofit.create(FavoriteService.class);
    // Retrofit 클래스로 interface 객체를 구현한다.

    retrofitAPI.getFavorite(userId).enqueue(new Callback<List<Favorite>>() {
        // interface 에서 정의했던 메소드 중 하나를 선언하고, 비동기 통신을 실행한다.
        // 통신이 완료되었을 때 이벤트를 처리하기 위해 Callback 리스너도 함께 등록한다.
        @Override
        public void onResponse(Call<List<Favorite>> call, Response<List<Favorite>> response) {
            if (response.isSuccessful()) { // 원활하게 통신이 이뤄졌을 때
                List<Favorite> data = response.body(); // 응답 내용을 변수에 입력
            } else { // 원활한 통신이 이뤄지지 않았을 때
                // 비정상 통신 대응
            }
        }
        // 통신 중 생각하지 못한 예외(네트워크 오류 등)가 발생되었을 때 호출된다.
        @Override
        public void onFailure(Call<List<Favorite>> call, Throwable t) {
            t.printStackTrace();
        }
    });
}

해당 부분에서는 Retrofit 객체를 생성하고, interface 객체를 구현한 후 통신이 원활하게 이뤄졌을 때, 원활하게 이뤄지지 못했을 때의 행동들을 구현해주면 된다.


🤗 결과

코드에 담지는 않았지만, 통신이 성공했을 때 리사이클러뷰로 즐겨찾기 리스트를 띄우는 것을 구현하였다. 성공적으로 서버에서 받아와 데이터를 출력하는 모습을 확인할 수 있다.

기본적으로 Retrofit 은 거의 모든 안드로이드 개발자가 사용하는 통신 라이브러리라고 해도 무방하니, 안드로이드 개발을 공부하고 있다면 꼭 알아두는 것이 좋다.


참고 및 출처

Retrofit2 '레트로핏' - 기본 사용법
Retrofit2 한글판 문서
Get Started With Retrofit 2 HTTP Client

profile
즐겁게 하자 🤭

0개의 댓글