본문 바로가기

프로그래밍/Kotlin

Kotlin - Retrofit 간단 사용법

Retrofit 간단 사용법

 

사용할 때마다 기존 개발 코드를 참고해서 복사하다보니 기억에 남지 않아서 간단하게 정리해 보려고 합니다.

 

 

1. Retrofit 라이브러리를 추가합니다.

 

build.gradle(app) 에 아래 코드를 추가합니다.

 

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

 

 

2. 인터넷 접속 권한을 추가합니다.

 

AndroidManifest.xml 파일에 권한을 추가합니다.

 

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

 

 

3. 기본 구성요소 4가지

- 응답받을 data class

- API 선언 interface

- API interface를 호출할 object

- 사용하는 Activity or Fragment 에서 호출

 

 

4. 응답받을 data class

응답 구조에 따라서 data class 수는 가변적입니다.

결과 안에 배열이 포함되어 있으면 해당 배열을 선언하는 data class를 따로 만들어 주면 됩니다.

파일을 나누지는 않아도 되지만 저는 파일 갯수가 많아지더라도 따로 나눕니다.

 

네이버 뉴스 검색을 예로 들어보겠습니다.

출력 결과는 아래와 같습니다. 

결과 내부에 item/items 항목을 보면 하위 배열 결과 입니다. 

 

그래서 Items.kt를 만들어서 아래와 같이 클래스를 구성했습니다.

data class Items(
    @SerializedName("title") var title: String = "",
    @SerializedName("originallink") var originallink: String = "",
    @SerializedName("link") var link: String = "",
    @SerializedName("description") var description: String = "",
    @SerializedName("pubDate") var pubDate: String = ""
) {}

 

그리고 Items를 리스트로 포함한 ResultGetSearchNews.kt를 만들어서 아래와 같이 클래스를 구성했습니다.

data class ResultGetSearchNews (
    @SerializedName("lastBuildDate") var lastBuildDate: String = "",
    @SerializedName("total") var total: Int = 0,
    @SerializedName("start") var start: Int = 0,
    @SerializedName("display") var display: Int = 0,
    @SerializedName("items") var items: List<Items>
){}

 

 

4. API 선언 interface

 

사용할 API를 interface 로 선언해야 합니다.

 

네이버 뉴스의 경우 XML로 응답받을지, JSON으로 응답받을지 선택하면 됩니다.

 

Api.kt 파일을 만들어서 아래와 같이 interface를 구성했습니다.

interface Api {
    @GET("v1/search/news.json")
    fun getSearchNews(
        @Header("X-Naver-Client-Id") clientId: String = "ID로 초기화해도 됩니다.",
        @Header("X-Naver-Client-Secret") clientSecret: String = "값을 직접 넣어도 됩니다",
        @Query("query") query: String,
        @Query("display") display: Int? = null,
        @Query("start") start: Int? = null
    ): Call<ResultGetSearchNews>
}

 

 

POST 방식의 경우 GET 방식과 조금 다릅니다.

@FormUrlEncoded 와 @Field 를 사용해야 합니다.

    @FormUrlEncoded
    @POST("v1/papago/n2mt")
    fun transferPapago(
        @Header("X-Naver-Client-Id") clientId: String,
        @Header("X-Naver-Client-Secret") clientSecret: String,
        @Field("source") source: String,
        @Field("target") target: String,
        @Field("text") text: String
    ): Call<ResultTransferPapago>

 

 

5. API interface를 호출할 object

 

API를 호출하고 서버에 접속하여 결과를 받아올 수 있는 object를 만듭니다.

 

NaverRepository.kt를 만들어서 아래와 같이 object를 구성했습니다.

object NaverRepository {

    private val api: Api //인터페이스 구현

    init {
        val retrofit = Retrofit.Builder()
                .baseUrl("https://openapi.naver.com/")
                .addConverterFactory(GsonConverterFactory.create())
                .build()

        api = retrofit.create(Api::class.java)
    }

    fun getSearchNews(query: String,
                         onSuccess: (news: List<Items>) -> Unit,
                         onError: () -> Unit ) {
        api.getSearchNews(query = query, display=100)
                .enqueue(object : Callback<ResultGetSearchNews> {
                    override fun onResponse(
                            call: Call<ResultGetSearchNews>,
                            response: Response<ResultGetSearchNews>
                    ) {
                        if (response.isSuccessful) {
                            val responseBody = response.body()

                            if (responseBody != null) {
                                onSuccess.invoke(responseBody.items)
                            } else {
                                onError.invoke()
                            }
                        } else {
                            onError.invoke()
                        }
                    }

                    override fun onFailure(call: Call<ResultGetSearchNews>, t: Throwable) {
                        onError.invoke()
                    }
                })
    }
}

 

 

6. 사용하는 Activity or Fragment 에서 호출

 

이제 사용할 준비는 끝났습니다.

Activity 나 Fragment 에서 호출만 하면 됩니다.

 

HomeFragment 에 아래와 같이 구성하였습니다.

키워드를 받아서 검색 버튼을 누르면, NaverRepository.getSearchNews()에 키워드를 전달하여 검색을 합니다.

결과는 onSearchNewsFetched()으로 받고, 에러가 발생하면 onError()로 들어오게 됩니다.

class HomeFragment : Fragment() {
    lateinit var root: View

    override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?,
                    savedInstanceState: Bundle? ): View? {
        root = inflater.inflate(R.layout.fragment_home, container, false)

        root.bSearch.setOnClickListener() {
            var keyword = root.eSearchWord.text.toString()
            getSearchNews(keyword)
        }

        return root
    }

    private fun getSearchNews(searchWord: String) {
        NaverRepository.getSearchNews(
            searchWord,
            ::onSearchNewsFetched,
            ::onError
        )
    }

    private fun onSearchNewsFetched(news: List<Items>) {
        root.tResult.text = news.toString()
    }

    private fun onError() {
        Toast.makeText(activity, "error result", Toast.LENGTH_SHORT).show()
    }
}

 

 

헷갈릴때마다 참고해야 겠습니다.

 

 

반응형