맨날 job만 쓰다가 최근에 선배가 SupervisorJob을 쓰는걸 보고
왜 쓰는 걸까 궁금해졌습니다.
결론 부터 말하면 에러 핸들링때문에 사용합니다.
부모 코루틴안 자식코루틴에서 에러가 발생할때
그냥 Job을 쓴다면 그위로 부모까지 에러가 전파되어 부모 코루틴까지 취소되어
나머지 자식 코루틴은 실행이 안됩니다.
하지만 SupervisorJob 을 쓴다면 에러발생시 부모까지 전파가 안되고
그아래 자식 코루틴만 취소 시키기 때문에 에러 전파의 방향이
단방향이 됩니다.
뭔 소리인지 감이 안잡히신다구요?
이제 코드로 같이보시죠
fun test() = runBlocking {
val downloadScope = CoroutineScope(Dispatchers.IO + Job())
val ftpScope = CoroutineScope(Dispatchers.Default + Job())
ftpScope.launch {
downloadScope.launch { downloadFile("file1", 1000) }
downloadScope.launch { downloadFile("file2", 200) }
downloadScope.launch { downloadFile("file3",600) }
downloadScope.launch { downloadFile("file4",700) }
downloadScope.launch { downloadFile("file5",500) }
}
}
suspend fun downloadFile(fileName: String, spend: Long) {
delay(spend)
println("download $fileName")
}
이렇게 부모 코루틴 안에서 돌아가는 5개의 자식 코루틴이 있다고 해봅시다.
download file2
download file5
download file3
download file4
download file1
코드를 실행했을때 문제없이 잘 실행하는 것을 알 수 있습니다.
ftpScope.launch {
downloadScope.launch { downloadFile("file1", 1000) }
downloadScope.launch { downloadFile("file2", 200) }
downloadScope.launch { downloadFile("file3",600) }
downloadScope.launch { downloadFile("file4",700) }
downloadScope.launch {
delay(300)
throw NetworkException("Internet Disconnected!!")
downloadFile("file5",500)
}
}
5개의 파일을 다운로드 하던중 1개에서 문제가 생겼다고 가정해봅시다.
download file2
Exception in thread "DefaultDispatcher-worker-4" ...
앗 이런 0.3 초쯤에 예외가 발생해서 0.2초에 다운로드 완료된
file2 말고는 다 다운로드가 취소됐어요 ㅠㅠ
하나가 취소되더라도 나머지는 다 받고 봐야하는데
정말 난감하죠?
val handler = CoroutineExceptionHandler{ _, e ->
println("catch in Handler!! error is $e")
}
ftpScope.launch {
downloadScope.launch { downloadFile("file1", 1000) }
downloadScope.launch { downloadFile("file2", 200) }
downloadScope.launch { downloadFile("file3",600) }
downloadScope.launch { downloadFile("file4",700) }
downloadScope.launch(handler) {
delay(300)
throw NetworkException("Internet Disconnected!!")
downloadFile("file5",500)
}
}
ExceptionHandler라... 얘라면 예외를 처리해서 정상 작동 할지도 몰라!
download file2
catch in Handler!! error is PackageName.NetworkException: Internet Disconnected!!
에러는 잡았지만 부모가 취소되는 것을 막지 못하네요 ㅠㅠ
val downloadScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
ftpScope.launch {
downloadScope.launch { downloadFile("file1", 1000) }
downloadScope.launch { downloadFile("file2", 200) }
downloadScope.launch { downloadFile("file3",600) }
downloadScope.launch { downloadFile("file4",700) }
downloadScope.launch(handler) {
delay(300)
throw NetworkException("Internet Disconnected!!")
downloadFile("file5",500)
}
}
이제 마지막남은 희망은 SupervisorJob 하나입니다 ㅠㅠ
어디 한번 볼까요?
download file2
catch in Handler!! error is PackageName.NetworkException:Internet Disconnected!!
download file3
download file4
download file1
이제 에러난 파일을 다운로드 하는 코루틴 하나만 취소하고
나머지 파일은 다운로드를 성공했어요!
코드에서 보셨던 것처럼 SupervisorJob을 적용하면
에러 전파가 부모까지 되지않고 그아래로만 전파해서
자식코루틴만을 취소시킵니다.
이로써 나머지 자식들은 온전하게 실행시킬 수 있게 되었죠.
적절하게 SupervisorJob을 활용한다면 비동기 처리를 더욱더
깔끔하게 할 수 있으니 잘 활용하도록 합시다.
supervisorScope라는 것도 비슷하니 한번 알아보세요!
이 글이 후배 안드로이드 개발자들에게 도움이 되면 좋겠습니다.