마스터Q&A 안드로이드는 안드로이드 개발자들의 질문과 답변을 위한 지식 커뮤니티 사이트입니다. 안드로이드펍에서 운영하고 있습니다. [사용법, 운영진]

자바 retrofit call<responsebody>를 코루틴으로 처리할때

0 추천

   public void onFailure(Throwable t, ApiClass.ErrorStatus status, String message, Call<ResponseBody> call, Callback<ResponseBody> responseBodyCallback) {
}

레트로핏에서 에러가 떨어졌을때 자체 구현한 fail 클래스더라구요 

이거를 코틀린의 코루틴으로 바꿨을때 Call<ResponseBody> call, Callback<ResponseBody> responseBodyCallback 

이두개를 어떻게 가져와야될까요?

아래 코드는 제 토이프로젝트의 코드로 테스트해보고 있는 코드입니다.

call<responsebody>를 리턴해서 가져오면 될거라 생각해서 이렇게 구현해봤습니다

fun test(categoryId: Int): Flow<ResponseBody> {
    return flow {
        val response = service.test(apiKey, categoryId).awaitResponse().body()
        emit(response!!)
    }
}
@GET("api/newBook.api")
suspend fun test(
    @Query("key") key : String,
    @Query("categoryId") categoryId : Int,
    @Query("output") output : String = "json"
) : Call<ResponseBody>
 
 
 
수원통학러 (3,570 포인트) 님이 2023년 2월 28일 질문

1개의 답변

0 추천

Retrofit 함수의 리턴값에 Callback을 사용할 필요가 없습니다. ResponseBody의 Body에 들어가는 타입을 직접 사용하셔도 됩니다. 기존 함수를 함수2() 와 같이 하나 더 만드셔서 기존 함수룰 사용하는 곳을 하나씩 함수2를 호출하조록 변경하시면 됩니다.
 

@GET("api/newBook.api")
suspend fun test2(
    @Query("key") key : String,
    @Query("categoryId") categoryId : Int,
    @Query("output") output : String = "json"
) : ResponseBody

fun test2(categoryId: Int): Flow<ResponseBody> {
    return flow {
        val response = service.test(apiKey, categoryId)
        emit(response.body!!)
    }
}

그리고 stream 형태로 처리하는 경우가 아니면 굳이 Flow로 처리할 필요는 없습니다. 그보다는 Response의 결과를 체크하고 적절한 클래스로 리턴하는 부분이 먼저 필요해 보입니다.

백그라운드 쓰레드에서 호출하는지도 점검하시구요.

 

spark (227,510 포인트) 님이 2023년 2월 28일 답변
spark님이 2023년 2월 28일 수정
public void onFailure(Throwable t, ApiClass.ErrorStatus status, String message, Call<ResponseBody> call, Callback<ResponseBody> responseBodyCallback) {
}
이코드가 제가 만든 코드가 아니고 회사코드인데 직접 메소드를 만드셔서 fail일때 에러처리하는 클래스 ErrorClass가 있다고할때 여기에 파라미터로 status, 에러메세지, call, callback객체를 넘기고 ErrorClass안에서 status값으로 enum 클래스로 상태값체크하고, 네트워크가 불안정할때 call과 callback으로 다시
| call.clone().enqueue(responseBodyCallback); 이렇게 요청을 하는 상태라서 현재 자바 코틀린섞여있구요 이걸 코틀린 코루틴으로 처리하려고합니다만 .. 막혔네요
Callback을 사용하실거면 굳이 코루틴 코드가 필요없어 보이는데요. 현재 사용하시는대로 사용하시면 되고 굳이 코틀린으로 변환하실필요 없어 보여요. 굳이 코루틴을 사용하고 싶으시면 onFailure를 코루틴 버전으로 하나 더 만드셔서 처리하는게 더 안전해 보여요.
기존거는 그냥 자바로 하려고 하지만, 신규 화면등은 코틀린으로 하려고 합니다
하지만 에러처리를 기존 자바에서 하던거랑은 맞추는게 나을거같아서 하려고하는데, onFailure를 만드는 방법만 있는걸까요?
이런 경우는 더더욱 기존 코드는 일단 놔두시고 코틀린 버전의 코드를 만드신 다음, 새화면에는  코틀린 버전만 적용하시는게 안전한 방법이예요. 코틀린 버전이 잘 동작하면 기존의 자바코드도 하나씩 코틀린으로 변환해 나가시구요.
코틀린 suspend function을 사용하면 굳이 콜백이 필요하지 않아요. 기존 자바코드를 억지로 맞추시는 것 보다는 코틀린용으로 함수나 클래스를 만드셔서 그걸 새로운 화면에 적용하시는게 코드 관리 차원에서 더 낫습니다.
그리고 코틀린으로 네트워크 레이어를 작성할 때는 안드로이드 개발자 가이드의 아키텍쳐 가이드를 보시면 도움이 되구요. 많이들 사용하는 방법은 코틀린에서 제공하는 Result클래스나 Either(https://subscription.packtpub.com/book/programming/9781787126367/5/ch05lvl1sec77/either) 같은 sealed class를 사용해서 결과를 감싸줍니다. 이렇게 하는 이유는 코루틴 스콥이 중첩이 되면 자식 코루틴 스콥에서 발생하는 exception을 최상위 스콥까지 강제로 올라가는 코루틴의 특성 때문에 안전하게 코딩을 하기 위한 목적과 functional programming을 장점을 사용하기 위한 것입니다. 코틀린에서는 자바처럼 Exception을 던지고 받는 방식을 자주 사용하는 것은 개발자들이 선호하는 방법은 아닙니다.
기존 함수에서 네트워크 체크하는 로직과 에러 처리 로직 등만 가져와서 사용하세요.
skydove님이 만든 라이브러리와 곤련 블로그도 코틀린으로 네트와 워크 처리를 할 때 어떻게 하는 것이 좋을지 방향을 잡는데 많은 도움이 됩니다. https://github.com/skydoves/sandwich
혹 필요하다면 callback을 Flow나 suspend function으로 변환해서 사용할 수는 있습니다.
callbackFlow(https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/callback-flow.html)나 suspendableCancellableCoroutine(https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/suspend-cancellable-coroutine.html) 을 참고하세요. 기존코드를 꼭 원하신다면 아마도 이 방법이 제일 수고가 적을 것 같아 보여요.
...