본문 바로가기
Programando/Android

[Android/Java] Retrofit2를 통해 RestAPI와 통신하기

이전에 포스팅했던 글이 오래 지나고 보니까 "어? 이걸 그대로 내버려둬도 되는건가?" 싶어서 다시! 새로 포스팅합니다.

구글 Directions API에 Parameter를 보내고 결과값을 Retrofit2 라이브러리를 통해 파싱합니다.

 

0. 종속성 추가

Retrofit2를 사용하기 위해서는 먼저 app 모듈의 build.gradle에 종속성을 추가해야 합니다.

dependensies {
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
}

 

1. 구글 Directions API Key 발급

Directions API를 이용해서 교통 정보를 얻어오려면 먼저 구글 클라우드 플랫폼에서 Directions API를 사용 설정하고 API KEY를 발급받아야 합니다.

  1. 구글 클라우드 플랫폼(https://console.cloud.google.com/?hl=ko)에서 프로젝트를 생성
  2. 프로젝트의 대시보드에서 'API' - 'API 개요로 이동'을 클릭
  3. API 및 서비스 화면에서 '+ API 및 서비스 사용 설정'을 클릭
  4. API 라이브러리에서 'Directions API'를 검색하고 제일 위에 뜨는 API를 선택
  5. Directions API 사용 설정을 클릭하고, Directions API 화면에서 사용자 인증 정보를 클릭
  6. 'API 및 서비스의 사용자 인증 정보'를 클릭하고 사용자 인증 정보 화면으로 이동
  7. '+ 사용자 인증 정보 만들기'를 눌러 'API 키'를 선택한다. 그럼 API 키가 생성되고 이를 복사

이제 이 API를 이용해서 정보를 얻어와 안드로이드에 표시해야 합니다.

 

2. Manifest에 권한 추가

RestAPI를 통해 데이터를 받아오기 위해서는 인터넷이 필요하므로 manifest 파일에 Internet 권한을 추가해야 합니다.

<uses-permission android:name="android.permission.INTERNET" />

 

3. RetrofitClient 생성

Directions API와 통신하기 위한 baseUrl을 설정하고 데이터 파싱 및 객체 정보를 반환할 수 있는 Retrofit 객체와 Json을 Java Class로 변환시켜줄 Gson 객체를 생성하는 부분을 만들어줍니다.

먼저, baseUrl은 고정된 주소로 지정합니다. Directions API에서 "https://maps.googleapis.com/maps/api/directions/" 부분은 변하지 않기 때문에 baseUrl로 지정했습니다. 중요한 점은 baseUrl은 꼭 ‘/’로 끝나야 오류가 생기지 않는다는 점입니다.

그리고 addConverterFactory(GsonConverterFactory.create(gson))은 Json 데이터를 POJO Class 형식으로 자동변환하기 위해 필요합니다.

  • RetrofitClient.java
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class RetrofitClient {

    private static Retrofit instance = null;
    private static Gson gson = new GsonBuilder().setLenient().create();

    private RetrofitClient() {
    }

    public static Retrofit getInstance() {
        if (instance == null) {
            instance = new Retrofit.Builder()
                    .baseUrl("https://maps.googleapis.com/maps/api/directions/")
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .build();
        }
        return instance;
    }

}

 

반응형

 

4. POJO Class 생성

API의 응답 예시를 확인하고, 출력에 따라서 POJO Class를 생성합니다.

제가 날린 요청에 돌아오는 결과 중에 필요한 부분은 아래와 같습니다. 이런 출력변수에 대응되는 POJO Class를 만들어주면 됩니다.

{
"routes" : [
      {
         "legs" : [
            {
               "arrival_time" : {
                  "text" : "오후 2:36",
                  "time_zone" : "Asia/Seoul",
                  "value" : 1587188188
               },
               "departure_time" : {
                  "text" : "오후 2:27",
                  "time_zone" : "Asia/Seoul",
                  "value" : 1587187653
               },
               "distance" : {
                  "text" : "1.2 km",
                  "value" : 1159
               },
               "duration" : {
                  "text" : "9분",
                  "value" : 535
               },
               "end_address" : "대한민국 서울특별시 중구 명동 세종대로 110",
               "end_location" : {
                  "lat" : 37.5662952,
                  "lng" : 126.9779451
               },
               "start_address" : "대한민국 서울특별시 종로구 종로1.2.3.4가동 사직로 161",
               "start_location" : {
                  "lat" : 37.57593689999999,
                  "lng" : 126.9768157
               },
               "steps" : [
                  {
                     "distance" : {
                        "text" : "0.4 km",
                        "value" : 364
                     },
                     "duration" : {
                        "text" : "6분",
                        "value" : 365
                     },
                     "end_location" : {
                        "lat" : 37.572674,
                        "lng" : 126.976481
                     },
                     "html_instructions" : "세종문화회관까지 도보",
                     "polyline" : {
                        "points" : "s`jdFcd_fWlSbA"
                     },
                     "start_location" : {
                        "lat" : 37.57593689999999,
                        "lng" : 126.9768157
                     },

             ... 생략 ...
}

POJO Class를 생성할 때, JSON 데이터의 속성명과 변수명 + 타입(ex String,Int,Boolean) 일치는 필수입니다. 혹은 @SerializedName 어노테이션을 통해 Json의 Key 값과 같도록 만들어줘야 합니다.

 

출력변수에 맞는 POJO Class 생성하기

  1. Directions API에 요청한 후에 받은 출력변수를 Copy 합니다.
  2. JSON to POJO Object Online Converter(https://freecodegenerators.com/json-to-pojo)에 들어갑니다.
  3. Copy해두었던 출력변수들을 Paste하고, Settings에서 Use Properties 부분을 체크한 후에 초록색 Convert 버튼을 누릅니다.
  4. 위의 사진처럼 오른쪽에 POJO Class를 자동으로 만들어주고, 아래에 Zip as File이라고 되어 있는 버튼을 눌러 다운받은 Zip 파일을 프로젝트에 추가해주면 됩니다.
  5. @JsonProperty 어노테이션은 위에서 언급했던 @SerializedName로 변경해야 합니다.

 

5. API Interface 생성

Directions API와 통신하기 위해 사용할 HTTP CRUD동작(메소드)들을 정의할 API Interface를 생성합니다.

GET 방식으로 데이터를 보내고, 가져오기 위해 @GET 요청 메서드에는 RetrofitClient에 작성한 baseUrl의 뒤에 오는 EndPoint를 지정하고, 동적으로 변경해야 하는 파라미터@Query 어노테이션을 이용해서 메서드를 호출할 때 값을 넘겨받아 주소에 포함시키도록 합니다. 마지막으로, 요청한 주소로부터 Json을 반환받는다면 위에서 만들어둔 POJO Class로 받을 수 있도록 Call을 return type으로 정해줍니다.

import java.util.List;

import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;

public interface RetrofitAPI {
    @GET("json?key=API_KEY")
    Call<Root> getDirections(
        @Query("origin") String origin,
        @Query("destination") String destination,
        @Query("mode") String mode,
        @Query("departure_time") String departure_time,
        @Query("alternatives") String alternatives,
        @Query("language") String language
    );
}

 

6. 요청 보내고 받기

처음에 만들었던 RetrofitClient를 통해 생성한 Retrofit 객체를 받아오고, 해당 객체를 이용해 Interface를 구현합니다. 통신 방법에는 enqueue를 이용하는 비동기 작업과 execute를 이용하는 동기 작업이 있습니다.

비동기 작업으로 실행한다면 통신 종료 후 이벤트 처리를 위해 Callback을 등록해야 하고, 동기 작업으로 실행한다면 AsyncTask 등을 통해 받아온 데이터를 가지고 UI 작업을 할 수 있습니다.

저는 비동기 작업으로 실행할 것이므로 enqueue를 이용하였습니다. 요청을 보내고 난 다음 결과는 두 가지로 나뉩니다. 통신에 성공했을 경우에는 onResponse, 통신에 실패했을 경우에는 onFailure로 나뉘는데 실패했을 경우에는 그에 따른 처리를 해주어야 합니다.

  • MainActivity.kt
    public void getData(String... params) {

        String origin = params[0];
        String destination = params[1];
        String mode = params[2];
        String departure_time = params[3];
        String alternatives = params[4];
        String language = params[5];

        Retrofit retrofit = RetrofitClient.getInstance();
        RetrofitAPI retrofitAPI = retrofit.create(RetrofitAPI.class);

        //큐에 삽입
        retrofitAPI.getDirections(origin, destination, mode, departure_time, alternatives, language).enqueue(new Callback<Root>() {
            //통신 성공
            @Override
            public void onResponse(@NonNull Call<Root> call, @NonNull Response<Root> response) {
                if (response.isSuccessful()) {
                    Root root = response.body();
                    if(root.getStatus().equals("OK")) {
                        // 데이터 처리
                        Step tempStep = root.getRoutes().get(0).getLegs().get(0).getSteps().get(0);
                        Log.d("Retrofit2 - Success", tempStep.getHtml_instructions());
                    } else {
                        Toast.makeText(getApplicationContext(), "서버에 문제가 발생했습니다.", Toast.LENGTH_SHORT).show();
                    }
                } else {
                    Toast.makeText(getApplicationContext(), "서버에 문제가 발생했습니다.", Toast.LENGTH_SHORT).show();
                    Log.d("Retrofit2 - Failure ", response.code() + " : " + response.message());
                }
            }

            //통신 실패
            @Override
            public void onFailure(@NonNull Call<Root> call, @NonNull Throwable t) {
                Toast.makeText(getApplicationContext(), "서버에 문제가 발생했습니다.", Toast.LENGTH_SHORT).show();
                t.printStackTrace();
            }
        });

    }

 

7. 통신 결과

반응형