본문 바로가기
Android

[Kotlin] Android 에서 Retrofit2 사용하여 API 호출하기

by bryan.oh 2023. 7. 25.
반응형

 

 

 

테스트 할 Empty Activity 를 생성합니다. (이제 생성 단계는 생략)

이름은 RestApiActivity 로 하고, Source Language 는 Kotlin

class RestApiActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rest_api)
    }
}

기본적으로 이렇게 코드가 나오는데, 아래와 같이 ViewBinding 으로 변경합니다.

class RestApiActivity : AppCompatActivity() {
    private lateinit var binding: ActivityRestApiBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityRestApiBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
    }
}

 

API

사용할 api 는 무료로 open 되어있는 휴일 검색 API 입니다. 가입 필요 없습니다~

https://date.nager.at/api/v2/publicholidays/{year}/{locale}

url 뒤에 year과 locale 만 입력하면 결과가 나옵니다.

 

Retrofit2

Retrofit은 안드로이드 및 Kotlin에서 네트워크 요청을 쉽게 처리하기 위한 라이브러리입니다. 

RESTful API와의 통신을 위해 매우 인기 있는 라이브러리로, 네트워크 요청을 선언적인 방식으로 작성할 수 있도록 도와줍니다.

최신 버전은 여기 에서 확인이 가능합니다.

라이브러리 추가

build.gradle 에 dependencies 에 아래 두개 항목을 추가합니다.

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

그리고 Sync Now 를 눌러줍니다.

 

Manifest 

인터넷 사용 권한을 추가합니다.

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

 

DataClass

api 를 호출하면 반환되는 형식이 JSON 이기 때문에, 이것을 data class 로 변환하도록

형식에 맞는 data class 를 생성합니다.

우선 리턴되는 형식은 다음과 같습니다.

[
  {
    "date":"2023-01-01",
    "localName":"새해",
    "name":"New Year's Day",
    "countryCode":"KR",
    "fixed":true,
    "global":true,
    "counties":null,
    "launchYear":null,
    "type":"Public"
  },
  ...생략
]

package를 먼저 생성하고 그 안에 class를 만듭니다.

package 이름은 models

models 페키지 아래에 Kotlin Class/File 생성 > Data class

이름은 PublicHolidays 

 

PublicHolidays.kt

data class PublicHolidays(
    @SerializedName("date") val date: Date,
    @SerializedName("localName") val dateName: String,
    @SerializedName("name") val engName: String,
    @SerializedName("countryCode") val locale: String,
    @SerializedName("fixed") val fixed: Boolean,
    @SerializedName("global") val global: Boolean,
    @SerializedName("counties") val counties: String?,
    @SerializedName("launchYear") val launchYear: String?,
    @SerializedName("type") val type: String
)

SerializeName 은 api 서버에서 받아온 json 의 key 이름입니다. val 뒤에있는 프로퍼티에 값을 전달합니다.

이름은 달라도 됩니다.

 

Retrofit Service Interface 

package com.example.test01.interfaces

import com.example.test01.models.PublicHolidays
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Path

interface DateApiService {
    @GET("/api/v2/publicholidays/{year}/{locale}")
    fun getHolidays(
        @Path("year") year: String,
        @Path("locale") locale: String
    ): Call<List<PublicHolidays>>
}

우선 models와 같은 level로 interfaces 라는 package 를 만들고 그 안에 생성합니다.

만약에 path variable이 아니라 /api/v2/publicholidays?year=2023&locale=KR 이었다면
@Query("year") year:String
이런식으로 Query 로 입력해야합니다.

 

사용하기

준비가 길었습니다.. 이제 사용할 차례네요.

다시 RestApiActivity.kt 로 와서 retrofit 을 선언하고 객체를 생성합니다.

package com.example.test01

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.test01.databinding.ActivityLifeBinding
import com.example.test01.databinding.ActivityRestApiBinding
import com.example.test01.interfaces.DateApiService
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

class RestApiActivity : AppCompatActivity() {

    // 여기부터
    val retrofit = Retrofit.Builder()
        .baseUrl("https://date.nager.at/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val dateApiService = retrofit.create(DateApiService::class.java)
    // 여기까지

    private lateinit var binding: ActivityRestApiBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityRestApiBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)


    }
}

그리고 버튼을 하나 추가하고, 클릭했을 때 dateApiService 를 사용하도록 해보겠습니다.

버튼은 layout file (activity_rest_api.xml) 에서 추가하시고, 버튼 텍스트와 id 를 입력한 후 

(저는 rest_get_button 로 id 를 지정했습니다. 그래서 아래 코드에 binding.restGetButton 으로 사용)

binding.restGetButton.setOnClickListener {
    dateApiService.getHolidays("2023", "KR")
        .enqueue(object: Callback<List<PublicHolidays>> {
            override fun onResponse(call: Call<List<PublicHolidays>>, response: Response<List<PublicHolidays>>) {
                if(response.isSuccessful.not()){
                    return
                }

                response.body()?.let{
                    Log.d("OK", it.toString())
                    it.forEachIndexed { index, publicHolidays ->
                        Log.d("DATA", "[$index] date = ${publicHolidays.date}, name = ${publicHolidays.dateName}")
                    }
                } ?: run {
                    Log.d("NG", "body is null")
                }
            }

            override fun onFailure(call: Call<List<PublicHolidays>>, t: Throwable) {
                Log.e("ERROR", t.toString())
                Toast.makeText(applicationContext, t.toString(), Toast.LENGTH_LONG).show()
            }

        })
}

 

MainActivity 에서 RestApiActivity 로 넘어오는 것은..
MainActivity 에서 버튼 하나 만들고 클릭했을 때, 아래 줄 코드를 실행하면 됩니다.
startActivity(Intent(this, RestApiActivity::class.java))

 

앱을 실행하고, RestApiActivity 로 넘어와서 restGetButton 버튼을 누르면 결과는..

D/DATA: [0] date = Sun Jan 01 00:00:00 GMT+09:00 2023, name = 새해
D/DATA: [1] date = Sat Jan 21 00:00:00 GMT+09:00 2023, name = 설날
D/DATA: [2] date = Mon Jan 23 00:00:00 GMT+09:00 2023, name = 설날
D/DATA: [3] date = Tue Jan 24 00:00:00 GMT+09:00 2023, name = 설날
D/DATA: [4] date = Wed Mar 01 00:00:00 GMT+09:00 2023, name = 3·1절
D/DATA: [5] date = Fri May 05 00:00:00 GMT+09:00 2023, name = 어린이날
D/DATA: [6] date = Sat May 27 00:00:00 GMT+09:00 2023, name = 부처님 오신 날
D/DATA: [7] date = Tue Jun 06 00:00:00 GMT+09:00 2023, name = 현충일
D/DATA: [8] date = Tue Aug 15 00:00:00 GMT+09:00 2023, name = 광복절
D/DATA: [9] date = Thu Sep 28 00:00:00 GMT+09:00 2023, name = 추석
D/DATA: [10] date = Fri Sep 29 00:00:00 GMT+09:00 2023, name = 추석
D/DATA: [11] date = Sat Sep 30 00:00:00 GMT+09:00 2023, name = 추석
D/DATA: [12] date = Tue Oct 03 00:00:00 GMT+09:00 2023, name = 개천절
D/DATA: [13] date = Mon Oct 09 00:00:00 GMT+09:00 2023, name = 한글날
D/DATA: [14] date = Mon Dec 25 00:00:00 GMT+09:00 2023, name = 크리스마스

 

이렇게 나옵니다.. 잘 되네요.

파이썬이랑 비교되네요. 단계가 너무 많아...

 

728x90
반응형

댓글