본문 바로가기

개발일지/Android

[Android] Retrofit2 활용하여 API 연동 실전 예제

1. 종속성 추가

Retrofit

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

/* OkHttp */
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2'

 

 

2. Manifest

인터넷 권한 설정

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

안드로이드에서는 http 지원 X → API 주소가 http일 경우 추가

**<application
        ...
        android:usesCleartextTraffic="true"
        android:theme="@style/Theme.AOS_RestAPI_with_Retrofit2">**

 

 

3. RetrofitClient 생성

baseURL은 꼭 ‘/’ 로 마쳐야 오류가 나지 않는다

Object 파일

RetrofitClient.kt

package com.example.taveconnect.retrofit

import com.example.taveconnect.GlobalApplication
import com.example.taveconnect.retrofit.RetrofitClient.okHttpClient
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.create
import java.io.IOException
import javax.inject.Singleton


@Module
@InstallIn(SingletonComponent::class)
object RetrofitClient {


    @Provides
    @Singleton
    fun okHttpClient(interceptor: AppInterceptor): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(interceptor)
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .build()
    }

    var gson = GsonBuilder().setLenient().create()

    private val client = Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .client(okHttpClient(AppInterceptor()))
        .build()





    fun getInstance() : Retrofit {
        return client
    }


    class AppInterceptor : Interceptor {
        @Throws(IOException::class)
        override fun intercept(chain: Interceptor.Chain) : Response = with(chain) {
            val accessToken = GlobalApplication.prefs.getString("Authorization", "") // ViewModel에서 지정한 key로 JWT 토큰을 가져온다.
            val newRequest = request().newBuilder()
                .addHeader("Authorization", accessToken) // 헤더에 authorization라는 key로 JWT 를 넣어준다.
                .build()
            proceed(newRequest)
        }
    }
}

 

 

 

4. Data Class 생성

해당 방식으로 json 데이터를 복붙하면 쉽게 데이터 클래스 생성 가능

MyRankData.kt

 

package com.example.taveconnect.rank

import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName

class MyRankData (

    @SerializedName("defeat")
    @Expose
    val defeat: Int,

    @SerializedName("draw")
    @Expose
    val draw: Int,

    @SerializedName("name")
    @Expose
    val name: String,

    @SerializedName("picture")
    @Expose
    val picture: String,

    @SerializedName("ranking")
    @Expose
    val ranking: Int,

    @SerializedName("victory")
    @Expose
    val victory: Int


)

 

 

5. API Interface 생성

RetrofitAPI.KT

 

package com.example.taveconnect.retrofit

import com.example.taveconnect.game.*
import com.example.taveconnect.login.ResponseLoginData
import com.example.taveconnect.rank.MyRankData
import com.example.taveconnect.rank.RankData
import com.example.taveconnect.rank.UsersRankData
import retrofit2.Call
import retrofit2.http.*

interface RetroiftAPI {

    // 게임 시작 API
    @GET("/games")
    fun getGameStart(
        @Query("difficulty") difficulty: String
    ): Call<GameStartData>



    // 게임 turn API
    @Headers("Content-Type: application/json;charset=UTF-8")
    @POST("/games")
    fun getGameTurn(
        @Body gameTurnDTO: GameTurnDTO
    ): Call<GameTurnData>


    @Headers("Content-Type: application/json;charset=UTF-8")
    @POST("/games/results")
    fun getGameEnd(
        @Body gameEndDTO: GameEndDTO,
    ): Call<GameEndData>



    @GET("/games/{gameIdx}")
    fun getGameRestart(
        @Path(value = "gameIdx") gameIdx : Int
    ): Call<GameRestartData>


    @GET("/games/review")
    fun getGameReview(
    ): Call<GameReviewData>



    @GET("/ranking")
    fun getMyRanking(
    ): Call<MyRankData>

    @GET("/ranking/users")
    fun getUsersRanking(
    ): Call<UsersRankData>


    @FormUrlEncoded
    @POST("/login")
    fun getLogin(
        @Field("accessToken") accessToken: String,
        @Field("refreshToken") refreshToken: String
    ): Call<ResponseLoginData>

    @GET("/api")
    fun getAPI(): Call<Void>
}

 

6. 적용

RankFragment.kt



val profileList = ArrayList<RankData>()


val rankRecyclerAdapter = CustomAdapter(profileList)


binding.rvRank.adapter = rankRecyclerAdapter
binding.rvRank.layoutManager = LinearLayoutManager(requireContext())

val rankAPI = RetrofitClient.getInstance().create(RetroiftAPI::class.java)

rankAPI.getUsersRanking().enqueue(object: Callback<UsersRankData> {
    override fun onResponse(call: Call<UsersRankData>, response: Response<UsersRankData>) {
        if (response.isSuccessful) {
            val userDataList = response.body()?.toList()
            userDataList?.forEachIndexed { index, userData ->
                profileList.add(RankData(userData.ranking, userData.picture, userData.name))
            }
            rankRecyclerAdapter.notifyDataSetChanged()
        }
    }

    override fun onFailure(call: Call<UsersRankData>, t: Throwable) {
        Log.d("UsersRankAPI", "실패")
    }
})

 

 

 

 

Retrofit2 통신 레퍼런스

[Kotlin] Retrofit2 + OkHttp로 API request 시작기

Retrofit - 2 (Simple Retrofit Example)

[안드로이드 Retrofit 2] @Query, @Path, @Post, log 확인방법

[Kotlin] Retrofit2