본문 바로가기

안드로이드

[안드로이드] 예제: Retrofit 라이브러리를 사용하여 영화 정보 얻어오기

Retrofit

Retrofit은 안드로이드에서 사용되는 Type-safe한 HttpClient 라이프러리이다. Type-safe란, 요청을 통해 전달받은 데이터를 프로그램에서 사용하는 형태의 객체로 받을 수 있음을 의미한다. Retrofit은 개발자에게 추상화를 제공한다. 만약 Retrofit이 없다면 개발자는 연결, 캐싱, 실패시 대응, 쓰레딩, 응답 분석, 오류 처리 등의 과정이 필요하다. 

 

Retrofit의 사용 방법

  1. 데이터 모델 생성
  2. 인터페이스
  3. 인더페이스 구현체 생성
  4. 구현체를 이용하여 데이터 요청

종속성 추가

retrofit을 사용하기 위한 기본적인 라이브러이이다.

implementation 'com.squareup.retrofit2:retrofit:2.7.2'
implementation 'com.squareup.retrofit2:converter-gson:2.7.2'

추가로  manifest.xml에 인터넷 권한을 허용해준다.

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

 

 

데이터 모델 생성

package com.example.sampleapp.retrofit

import androidx.lifecycle.LiveData
import com.example.sampleapp.retrofit.Movie
import com.google.gson.annotations.SerializedName

data class UpComingMovie(
    @SerializedName("page") val page: String,
    @SerializedName("results") val movieList: List<Movie>
)



data class Movie (
    @SerializedName("title") val title: String,
    @SerializedName("original_title") val original_title: String,
    @SerializedName("poster_path") val poster_path: String,
    @SerializedName("overview") val overview: String,
    @SerializedName("backdrop_path") val backdrop_path: String,
    @SerializedName("release_date") val release_date: String
    )

JSON 데이터를 담기 위한 data class를 구현한다. 이는 실제 전달 받은 데이터 모델을 보고 필요한 필드만 작성하면 된다. 이때 중요한점이 변수명과 전달 받을 json의 변수명을 일치시켜야한다. 만약 본인의 고유한 이름을 사용하고 싶은 경우 위와 같이 annotaion을 사용한다. @SerializedName에 api에서 사용하는 변수명을 똑같이 입력하면 된다.

 

 

인터페이스 구현

package com.example.sampleapp.retrofit

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

interface MovieService {
    @GET("movie/upcoming")
    fun getUpcomingMovie(
        @Query("api_key") api_key : String="INPUT_YOUR_API_KEY",
        @Query("language") language : String="en-US", //korean: ko-KR
        @Query("page") page : Int =1
    ): Call<UpComingMovie>
}

Retrofit은 인터페이스에 정의된 값들을 API로 전환해준다. 리턴값은 우리가 전달받을 객체의 모델을 써주면 된다. 그리고 각종 질의에 필요한 내용을 써준다. 위의 쿼리의 경우.../movie/upcoming?api_key=<>&language=en-US&page=1와 같은의미이다.

 

 

인터페이스 구현체

object RetrofitAPI {
    private var instance : Retrofit? = null
    private val gson = GsonBuilder().setLenient().create()

    fun getInstnace() : Retrofit {
        if(instance == null){
            instance = Retrofit.Builder()
                .baseUrl("https://api.themoviedb.org/3/")
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        }
        return instance!!
    }
}

위의 인터페이스를 실제 구현체로 생성한다.

 

 

 

구현체를 이용하여 데이터 요청 - 비동기적 호출

 api.getUpcomingMovie().enqueue(object : Callback<UpComingMovie> {
            override fun onResponse(call: Call<UpComingMovie>, response: Response<UpComingMovie>) {
                data.value = response.body()
                Log.d("MovieDataList",data.value?.movieList.toString())
            }
            // Error case is left out for brevity.
            override fun onFailure(call: Call<UpComingMovie>, t: Throwable) {
                t.stackTrace
            }
        })

이번 문서에서는 실제 사용보다는 데이터를 가져올 수 있다 정도로만 간략하게 구현하였다. Callback 방식으로 비동기적으로 데이터를 요청하여 전달받고 있다. 그리고 onFailure에서 전달받는 실패란, 요청한 API 서버의 다운 프로그래머의 잘못된 query  등의 문제를 의미한다. 다시말하면 403 error와 같은 것은 사실 정상적인 응답으로 본다. 따라서 이를 잘 처리할 필요가 있다. reponse.code() 등을 활용하거나 reponse.isSuccessful()을 활용한다.