@PATCH("END_POINT")
fun changeUserInfo(@Body user: User):Call<Void>
RetrofitClient.userService.changeUserInfo(user)
.enqueue(object : Callback<Void>{
override fun onResponse(call: Call<Void>, response: Response<Void>) {
if (response.isSuccessful){
...
} else {
...
}
}
override fun onFailure(call: Call<Void>, t: Throwable) {
Log.e(TAG, t.toString())
}
})
Call을 사용해 서버에 요청을 보낼 때, 각각의 Call은 자체적으로 HTTP 요청과 응답 쌍을 생성한다. Call은 execute()를 사용해 동기적으로, 또는 enqueue()를 사용해 비동기적으로 실행될 수 있다.
execute()는 동기적으로 요청을 보내고 응답을 반환한다. execute()를 사용해서 요청을 하면 해당 요청이 차단되고 반환받은 응답을 바로 사용할 수 있다.
하지만 이 메서드를 사용하는건 권장되지 않는다. Retrofit에서 동기 호출은 메인 쓰레드에서 실행된다. 이것은 곧 execute()가 실행되는 동안 UI가 차단된다는 것을 의미하고, 이 기간동안 유저와 화면 간의 상호작용은 불가능하다.
enqueue()는 비동기적으로 요청을 보내고 응답을 반환한다. 따라서 execute()와 다르게 UI를 차단하지 않고, 서버와의 통신 중에도 유저와 화면 간의 상호작용이 가능하기 때문에 권장되는 방법이다.
@POST("END_POINT")
suspend fun login(@Body user: User): Response<Void>
suspend fun login(user: User) {
try {
val response = RetrofitClient.userService.login(user)
if (response.isSuccessful){
...
}else {
...
}
}catch (e: Exception){
Log.e(TAG, e.toString())
}
}
Response를 사용하면 요청 이후의 응답을 받을 수 있다. Response는 성공일 수도, 실패일 수도 있기 때문에 각 케이스에 대한 핸들링을 해줘야 하는데, Response를 사용할 경우 Call.enqueue()를 사용할 때처럼 Callback methods(onResponse, onFailure)가 아닌 위 예제처럼 try ~ catch를 사용하거나 다른 방식을 사용해서 각 케이스에 대한 핸들링을 해줘야 한다.
Call은 서버에 대한 요청과 응답 결과에 대한 반환을 한 번에 수행하고,
Response는 요청 이후 응답 결과에 대한 반환만 수행한다. 코드를 보면 Call.enqueue()를 사용했을 때는 응답 결과의 성공 유무에 대해 직관적으로 처리할 수 있다는 장점이 있고, Response를 사용했을 경우 조금 더 간결하게 코드를 작성할 수 있다는 장점이 있다. 둘 중 무엇을 사용하든 제대로만 쓴다면 문제는 없지만, RxJava나 Coroutine를 사용해서 서버와 통신하고자 한다면 Call.enqueue()를 사용할 필요가 없기 때문에 Response를 사용하는 것이 더 좋을 것 같다. 나는 Call보다 Response를 사용할 때 코드가 좀 더 간결해지는게 좋아서 Response를 선호한다.
이 라이브러리를 사용하면 Retrofit의 Response를 코틀린의 Result 클래스로 모델링 할 수 있다. Response와 비교했을 때 큰 차이는 없는 듯 해서 취향에 맞게 사용하면 될 것 같다. 다만 반환값이 Void일 경우에는 에러가 발생하기 때문에, 이런 경우는 Response로 대체하고 있다.
Response
suspend fun idCheck(user_id: String) {
val response = RetrofitClient.userService.idCheck(user_id)
if (response.isSuccessful){
val body = response.body()
body?.let { ... }
}else {
...
}
}
Result
suspend fun idCheck(user_id: String) {
val result = RetrofitClient.userService.idCheck(user_id)
if (result.isSuccess) {
val body = result.getOrNull()
body?.let { ... }
} else {
Log.e(TAG, result.toString())
}
}
result.isSuccess
: 응답 결과가 성공적일 경우 true를 반환한다.
result.isFailure
: 응답에 실패했을 경우 true를 반환한다.
getOrNull()
: 응답 결과가 성공적인 경우 캡슐화된 값을 반환하고, 실패했을 경우 null을 반환한다.
https://howtodoinjava.com/retrofit2/retrofit-sync-async-calls/
https://stackoverflow.com/questions/64124670/call-or-response-in-retrofit
https://square.github.io/retrofit/2.x/retrofit/retrofit2/Call.html
https://square.github.io/retrofit/2.x/retrofit/retrofit2/Callback.html
https://square.github.io/retrofit/2.x/retrofit/retrofit2/Response.html
https://jeongupark-study-house.tistory.com/208
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result/