안드로이드에서 서버와 REST API 통신을 위해 자주 사용하는 라이브러리이다. 다른 통신 라이브러리보다 성능이 뛰어나며 가독성이 좋다는 장점을 가지고 있다.
gradle 파일에 retrofit2 관련 코드를 추가한다.
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
manifest 파일에 네트워크 권한을 추가한다.
<uses-permission-sdk-23 android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
🔸android.permission.INTERNET : 앱에서 네트워크 소켓을 열 수 있다.
🔸android.permission.ACCESS_NETWORK_STATE : 앱에서 네트워크에 관한 정보에 접근할 수 있다.
서버와 통신하기 위해서는 HTTP 통신 기능의 객체를 생성하여 사용한다. Retrofit 객체는 쉽게 HTTP 메소드를 호출할 수 있도록 도와준다. 그러나 통신이 필요할 때마다 동일한 작업을 수행하는 retrofit 객체를 새롭게 생성한다면 메모리 낭비일 것이다. 따라서 최초 생성한 retrofit 객체를 호출해서 사용할 것이다.
// 싱글톤 패턴
// 하나의 Retrofit 객체만를 생성하여 재사용
object RetrofitClient {
private var instance: Retrofit?= null
private val BASE_URL = "URL" // 서버 API
fun getInstance() : Retrofit {
if(instance == null){
instance = Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return instance!!
}
}
로컬 로그인(SNS 연동 로그인x)을 위해 사용한 예시이다.
private val retrofit: Retrofit = RetrofitClient.getInstance() // RetrofitClient의 instance 불러오기
private val loginApi: LoginService = retrofit.create(LoginService::class.java) // retrofit이 interface 구현
Runnable {
loginApi.logInLocal(LogInLocalReq(id, pw)).enqueue(object : Callback<BaseRes>{
// 전송 성공
override fun onResponse(call: Call<BaseRes>, response: Response<BaseRes>) {
if(response.isSuccessful) { // <--> response.code == 200
// 성공 처리
} else {
// 전송은 성공 but 에러
}
}
// 전송 실패
override fun onFailure(call: Call<BaseRes>, t: Throwable) {
Log.d("태그", t.message!!)
}
})
}.run()
🧨 서버에서 제공하는 API의 변수 타입과 이름에 맞게 작성해야 한다.
import retrofit2.Call
import retrofit2.http.POST
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.PATCH
interface LoginService {
@POST("users/logIn")
fun logInLocal(@Body Info: LogInLocalReq): Call<BaseRes>
}
import com.google.gson.annotations.SerializedName
data class LogInLocalReq(
@SerializedName("id") val id: String,
@SerializedName("pwd") val pwd: String
)
import com.google.gson.annotations.SerializedName
data class BaseRes(
@SerializedName("code") val code: Int,
@SerializedName("isSuccess") val isSuccess: Boolean,
@SerializedName("message") val message: String,
@SerializedName("result") val result: BaseResult?
)
data class BaseResult(
val accessToken: String,
val accessTokenExpiresIn: String,
val grantType: String,
val refreshToken: String
)