광산김가네

[Kotlin] Retrofit 기초 공부(1) 본문

카테고리 없음

[Kotlin] Retrofit 기초 공부(1)

MinseoKim 2023. 2. 2. 04:21

근래 kotlin 관련 프로젝트를 2개 진행하고있는데 둘다 로그인-회원가입 파트를 맡게되었다,^,,,^

한 프로젝트는 해커톤때 진행했던 프로젝트를 이어서하는데,..그때도 api통신에서 막혀서 완성을 못했었다.

문제의 retrofit..다시 도전해보려한다

 

라이브러리: Retrofit2 

참고블로그 https://bamdule.tistory.com/266

1. build.gradle, AndroidManifest.xml 추가

build.gradle

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

AndroidManifest.xml

 compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
dependencies {  
     //Retrofit2
    implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
    implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
    implementation 'com.squareup.okhttp3:okhttp:4.9.1'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.9.0'
    implementation "com.squareup.okhttp3:okhttp-urlconnection:4.9.1"  
  }

2. retrofit 코드 작성

공식문서에 나와있듯이 크게 3가지단계로 구성된다

1. retrofit 객체 생성

2. interface 생성 ( api 메소드, 전달할 body나 쿼리값을 지정해주는 함수)

3.  2번에서 선언한 함수 사용

1) retrofit객체 생성

retrofit builder를 이용한 getClient함수로 Retrofit의 객체를 생성해주는 함수를 작성해줬다

이때 해당함수는 Singleton 패턴으로 만약 객체있다면 만들지않고 생성되어있는 객체를 반환해준다

object RetrofitClient {
    //retrofit 객체 생성
    private lateinit var retrofitClient:Retrofit

    fun getClient(baseUrl:String): Retrofit?{
        Log.d(TAG,"retrofitClient - getClient() called")
        //아직 retrofit 객체가 생성되지않았다면
        if(retrofitClient == null){
            retrofitClient = Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build()
        }
        return retrofitClient
    }
}

 

+) Post body객체 생성

아래의 interface에 있는 함수의 반환과 요청이 보통 json 객체로 구성되어있는데

미리 data class로 선언하고 사용해주면된다

나의 경우 post 메소드로 api를 호출할건데, 필요한 정보로는 아래의 body값이였다.

따라서 이를 따로 data class 객체로 선언해주었다.

import com.google.gson.annotations.SerializedName

data class UserSignUp(
    @SerializedName("email")val email:String,
    @SerializedName("password")val password:String
)

+++아직 해결되지않은 의문이있는데.. request는 아니지만 response같은 경우 사용을 안해도되는 필드값들이있다

이를테면 isSuccess 나 statusMsg와 같은 서버에서 지정한 메세지??

이렇게 사용하지않는 필드값들도 무조건 객체로 다 선언해서 받아줘야되는지 의문이다

flutter같은 경우는 굳이 객체로 안감싸줘도 []<- 이렇게 배열처럼 갖다쓸수있는데 음..

 

3) Interface  선언

위의 과정에 더불어 url의 path를 하드코딩하지않고 api class를 따로파서 정의해줬다.

package 패키지.data.api

import 패키지.data.api.API.SIGNUP
import 패키지.model.UserSignUp
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.POST
import retrofit2.http.Query

interface ISignUp {
    @POST(SIGNUP)
    fun signUp(@Body userSignUp: UserSignUp): Call<UserSignUp>
}

근데 사실 하드코딩을 한다고해서 어떤게 더 좋은지는 잘모르겠어서..그냥 다른 함수들은 path string값으로 넣어줬당

 

4) retrofitmanager 선언; callback 

class RetrofitManager {
    companion object{
        val instance= RetrofitManager()
    }

    private val iSignUp:ISignUp? = RetrofitClient.getClient(API.BASE_URL)?.create(ISignUp::class.java)
    fun signUp(userSignUp: UserSignUp,completion:(UserSignUp)->Unit){
        val userA =UserSignUp("s202000529@hufs-gsuite.kr","kimwest00")
        val call = iSignUp?.signUp(userSignUp=userA).let{
            it
        }?:return

        call.enqueue(object: retrofit2.Callback<UserSignUp>{
            override fun onResponse(call: Call<UserSignUp>, response: Response<UserSignUp>) {
                if(response.isSuccessful){
                    Log.d("Post","success ${response}")
                }
                else {
                    Log.d("Post", "success,but ${response.errorBody()}")
                }
            }

            override fun onFailure(call: Call<UserSignUp>, t: Throwable) {
                Log.d("Post","fail ${t}")
            }
        })

}
}