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

코루틴 레트로핏 익셉션

0 추천
코루틴이랑 레트로핏이랑 같이써서 서버통신까지 정상적으로 됩니다만

와이파이, 모바일네트워크 끄면 보통 그냥 코루틴이 아닌 기본형?레트로핏  쓰면

onresponse와 onfailure가 있을때 onfailure로 타잖아요

근데 코루틴을 쓰면 try-catch를 써놔도 와이파이, 모바일네트워크끄면 앱이 죽던데..

어떻게 막아야되는지 코루틴은 onfailure하는 기능이 어떤건가요..
수원통학러 (3,570 포인트) 님이 2021년 7월 16일 질문

2개의 답변

0 추천

코루틴에서 제일 어려운 부분 중에 하나가 예외 처리와 작업 취소 입니다. Coroutine scope이 하나만 존재하는 아주 단순한 구조라면 try catch 가 예상대로 동작을 하지만 child scope이 존재하는 경우라면 try catch가 예상대로 동작하지 않습니다. 그건 코루틴이 예외를 내부적으로 처리히서 Job hiearchy의 상위 트리로 전달하기 때문인데요. 크케 두가지 옵션이 존재합니다.

코루틴에 exception handler를 다는 방법입니다. 

val handler = CoroutineExceptionHandler { _, exception -> 
    println("CoroutineExceptionHandler got $exception") 
}
val job = GlobalScope.launch(handler) { // root coroutine, running in GlobalScope
    throw AssertionError()
}
val deferred = GlobalScope.async(handler) { // also root, but async instead of launch
    throw ArithmeticException() // Nothing will be printed, relying on user to call deferred.await()
}
joinAll(job, deferred)

다른 방법은 Retrofit이 Response 객체를 리턴하도록 해보세요. 이렇게 하면 아마 try -catch를 사용할 수 있을 겁니다.

코루틴을 계속 사용하실 계획이시면 코루틴 페이지에 가셔서 에러 핸들링과 작업취소에 대한 부분을 꼼꼼하게 읽어보시길 권해드립니다.

https://kotlinlang.org/docs/exception-handling.html

아래 블로그도 읽어 볼 만합니다.

https://www.techyourchance.com/kotlin-coroutines-android-reference-guide/

spark (226,720 포인트) 님이 2021년 7월 16일 답변
spark님이 2021년 7월 17일 수정
0 추천

Edit: 테스트 해보니 Coroutin scope이 하나일 때는 응답 데이터 타입을 Response로 하지 않아도 (luanch builder사용) try catch가 잘 동작합니다. 만약 이 scope안에서 다른 scope이 생성된다면 그건 catch 바로 하시기 힘들거예요. 코틀린을 쓸 때는 Exception을 감싸서 Success나 Error을 나타내는 sealed class 로 바꾸어서 리턴하는 것이 랭귀지의 디자인상 처리하기가 훨씬 수월합니다. 네트워크 호출하는 부분을 먼저 try-catch로 처리하시고 여기서 리턴되는 결과값을 가져다 쓰세요.

sead class ApiResult<out T> {
   data class Error(val cause: Throwable): ApiResult<Nothing>()
   data class Success(val data: T): ApiResult<T>()
}


interface StackOverflowApi {
    @GET("2.3/questions?page=1&pagesize=10&order=desc&sort=activity&site=stackoverflow")
    suspend fun getQuestions(): QuestionsResponseSchema
}

// ApiService는 코
class RemoteDataSource(
   private val stackOverflowApi: StackOverflowApi
) {
   suspend fun getQuestions(): ApiResult<QuestionsResponseSchema> {
       return try {
           ApiResult.Success(stackOverflowApi.getQuestions())
       } catch (e: Exception) {
          ApiResult.Error(e)
       }
  }
 
}

 

위의 try-catch 부분만 빼내세 재사용할 수 있는 클래스나 함수를 만들어 쓰시면 여러 서비스에서 사용하실 수 있을듯 합니다..

spark (226,720 포인트) 님이 2021년 7월 17일 답변
...