Retrofit2 사용법

쿵ㅇ양·2024년 2월 1일
0

Android

목록 보기
2/30

후......
서버랑 api 연결을 시작했다..
api 명세서도 볼 줄 몰랐던 나는 이틀을 api에 대해 공부하고 서버분에게 질문했다
다행히 서버분이 안드로이드도 다뤄본 경험이 있으셔서 정말 많은 도움을 받았다(마이프로필 api 담당자님.. 정말 감사합니다..!)
그리고 지금 어제?? 아니 오늘 새벽 화면에 서버에서 내가 얻고 싶은 데이터만 가져와 화면에 뿌리는 것에 성공함!! 진짜 너무 뿌듯했다~~

우선,, api 명세서를 읽어보자!

1. 요청

Path Variable, Query String, Request Header, Request Body 로 이루어짐!!

  1. Request Header
    클라이언트 자체에 대한 자세한 정보를 포함하는 헤더
    우리는 Authorization(인증 토큰을 서버로 보낼 때 쓰이는 헤더)를 씀
    아직.. 로그인 토큰이 발급되지 않아 우선은 하드코딩해서 넣음
    발급되면 새로 업로드하겠슴!

  2. Path Variable
    경로를 변수로서 사용하는 것
    어떤 resource를 식별하고 싶을때 사용
    우리는 프로필 수정하거나 삭제할때 어떤 프로필을 수정하거나 삭제할지 정해줌!!

/users/123 # 아이디가 123인 사용자를 가져온다.

@Path 쓰고 경로 변수 넣어줌

 @PATCH("/myprofiles/{profile-id}")
    suspend fun patchProfile(@Path(value = "profile-id") profile_id : Long, @Body patchData: RequestPatchProfile) : Response<PatchMyprofile>
}
  1. Query String
    식별된 파라미터 경로
    정렬이나 필터링을 할때 사용
    /users?id=123  # 아이디가 123인 사용자를 가져온다.
    ``

4.Request Body
서버에 요청 보내는 메세지???같은거
@Body를 쓰고 뒤에 요청 바디의 변수들 넣어준 데이터 클래스 넣어주기

 @PATCH("/myprofiles/{profile-id}")
    suspend fun patchProfile(@Path(value = "profile-id") profile_id : Long, @Body patchData: RequestPatchProfile) : Response<PatchMyprofile>
}

Retrofit2 사용법

1. Manifest.xml 인터넷 추가

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

2. gradle 추가

implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation ("com.squareup.retrofit2:converter-gson:2.9.0")

3. Retrofit을 호출을 위한 Api interface생성

사용할 HTTP메서드 정의함

interface MainProfile {
    
     //endpoint: 베이스url 뒤에 붙음
    @GET("/myprofiles")
    
    //임시로 넣어준 값
    @Headers("member-id: 1")
    
 //메서드 getData()
//Call<클래스>: API 요청 응답에 성공 할 경우, 전달 받을 데이터를 저장 할 데이터클래스
//여기서 가장 상위클래인 데이터 클래스 넣어주기!!!!!!!!
   	fun getData(): Call<MainProfileData>
    
    

}

4. Retrofit 인스턴스 생성

앱에서 서버 호출이 필요한 곳마다 인터페이스를 사용해야 하는데, 인터페이스를 여러 번 구현하지 않고, 한 번만 구현해 놓고 필요한 곳에서 사용하기위해
-> 코틀린의 object 사용
-> object는 singleton 이기 때문에 전역 변수처럼 앱의 모든 곳에서 접근 가능

object RetrofitClient {
    
    //baseUrl은 꼭 / 로 끝나야 함
    private const val BASE_URL = "base url 넣어주기"

    private const val MEMBER_ID_HEADER = "member-id"
    private const val TEMP_MEMBER_ID = "1"

    // Retrofit 인스턴스 생성
    private val retrofit: Retrofit by lazy {
        val client = OkHttpClient.Builder()
            .addInterceptor { chain ->
                val originalRequest: Request = chain.request()
                val requestWithHeaders: Request = originalRequest.newBuilder()
                    .header(MEMBER_ID_HEADER, TEMP_MEMBER_ID)
                    .build()
                chain.proceed(requestWithHeaders)
            }
            .build()

        // Retrofit 빌더를 사용하여 Retrofit 인스턴스 생성
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .client(client)
  //addConverterFactory() 함수로 데이터 파싱 역할자를 지정
  .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    
    //Retrofit 인스턴스를 사용하여 MainProfile 서비스 인터페이스 생성
    // 실제 HTTP 요청을 정의하는 메서드를 포함
    val mainProfile: MainProfile by lazy {
        retrofit.create(MainProfile::class.java)
    }
}

5. api 명세서에서 주신 응답 보고 데이터 클래스 생성

우린 응답이 좀 길고 변수가 많았기 때문에
안드로이드 스튜디오에서 자동으로 변환해주는 기능이용해서 변환하고 애노테이션추가.. 엄청많은 하위 데이터 클래스들이 생겼다

data class MainProfileData(
    @SerializedName("code")
    val code: String,
    @SerializedName("isSuccess")
    val isSuccess: Boolean,
    @SerializedName("message")
    val message: String,
    @SerializedName("result")
    val result: Result
)

6. 프래그먼트에서 호출하고 데이터 가져오기

여기서 중요한건!!!
가장 여러 데이터 클래스 중 가장 상위클래스인 데이터 클래스에 응답 넣어주기!! 이거때문에 계속 해맴 처음에 하위클래스를 넣어주니 변수들의 데이터가 널이 나와서 계속 해매다가 서버분이 깃허브에 올린 코드보시고 사진에 글까지 그려주시면서 알려주심...!!🫶
Retrofit을 사용하여 서버에서 데이터를 가져오는 과정

//RetrofitClient 객체의 mainProfile 서비스 인터페이스를 사용하여 데이터를 가져오는 HTTP 요청 생성
//MainProfileData는 서버에서 받은 응답 데이터를 담는 클래스
//콜백 함수는 서버 통신 성공 또는 실패 시에 호출
RetrofitClient.mainProfile.getData().enqueue(object : Callback<MainProfileData> {
            
            // 서버 통신 실패 시의 작업
            override fun onFailure(call: Call<MainProfileData>, t: Throwable) {
                Log.e("실패", t.toString())
            }


            //서버에서 응답이 도착한 경우 호출되는 메서드
            //response 객체에는 서버에서 받은 응답이 포함
            //이 메서드에서는 응답을 분석하고 처리
            override fun onResponse(call: Call<MainProfileData>, response: Response<MainProfileData>) {
                
           //서버 응답에서 데이터를 추출
          //response.body()는 서버에서 받은 응답 본문을 말함
         //MainProfileData 클래스의 객체로 변환->하위클래스 데이터 이용하기위해
                val repos: MainProfileData? = response.body()
                
                if (repos != null) {
                    
                  //MainProfileData 객체에서 프로필 데이터를 추출
                    val frontFeatures: List<FrontFeature>? = repos.result.myprofiles?.flatMap { profile ->
                        profile.frontFeatures
                    }
                    if (frontFeatures != null) {
                        multiList.clear()
                        
                        //frontFeatures의 데이터 중 필요한 데이터만 추출해서 리스트에 넣어줌
                        frontFeatures?.forEach { frontFeature ->
                            if (frontFeature.featureId == 1) {
                                multiList.add(
                                    MultiProfileData(R.drawable.myprofile_character, frontFeature.value, frontFeature.value)
                                )
                                Log.d("FrontFeature key", frontFeature.key ?: "Key is null")
                                Log.d("FrontFeature value", frontFeature.value ?: "Value is null")
                            }
                        }

                        binding.mainProfileVp.setCurrentItem(0, false)

                        // 어댑터에 업데이트된 multiList를 제출
                        vpadapter.submitList(multiList)
                        Log.d("성공티비","success")
                        Log.d("FrontFeature List", multiList.toString())
                    } else {
                        Log.e("실패", "front_features 데이터가 null입니다.")
                    }
                } else {
                    Log.e("실패", "응답 데이터가 null입니다.")
                    Log.e("Response", "${response.code()}")
                }
            }
        })

    }
profile
개발을 공부하고 있는 대학생

0개의 댓글

관련 채용 정보