android 개발자를 위한 Dispatch Group
앞선 글(https://als2019.tistory.com/123)에서 설명한 것 처럼 iOS는 비동기 환경에서 실행된 다수 개의 Task 처리 완료 시 결과를 받아 처리할 수 있는 Dispatch Group을 지원합니다.
android는 Dispatch Group을 지원하지 않지만 @Synchronized를 사용하면 iOS의 Dispatch Group과 동일하게 사용할 수 있습니다.
이글에서는 android 개발자를 위한 Dispatch Group에 대해 설명하도록 하겠습니다.
아래와 같이 두개의 Network API를 호출하고 비동기로 결과를 받는 코드가 있다고 가정해보겠습니다.
MyNetworkModel.getList(offset: 0, limit: 20){ result ->
// 작업할 내용
}
MyNetworkModel.getInfo(myInfo: userId){ result ->
// 작업할 내용
}
저는 여기서 두개의 결과를 모두 받고 이후 처리를 하고자 합니다.
그럴 경우 간단하게 아래와 같이 코드를 추가할 수 있습니다.
var remainCount by MySynchronize(0)
MyNetworkModel.getList(offset: 0, limit: 20){ result ->
// 작업할 내용
remainCount -= 1
if (remainCount == 0) {
// 완료 후 처리할 작업
}
}
MyNetworkModel.getInfo(myInfo: userId){ result ->
// 작업할 내용
remainCount -= 1
if (remainCount == 0) {
// 완료 후 처리할 작업
}
}
위 코드는 왠지 부담스러워 보입니다.
그 이유는 어떤 Task가 작업 완료 Task인지 알 수 없어 모든 Task에 완료 여부를 체크하는 코드가 들어가기 때문입니다.
iOS에서는 멀티 Task 환경에서 작업 완료를 체크하는 Dispatch Group을 지원해 이를 사용해 Group에 속한 모든 작업의 완료를 확인 할 수 있는데 하는데 android에서는 이를 지원하지 않습니다.
얼핏 생각하기로 코루틴을 사용해서 해결하면 되지 않나라고 생각할 수 있지만 앞서 언급한 것과 같이 Network 호출 결과를 비동기로 받는 것이기 때문에 코루틴을 사용해서 해결하기가 곤란한 문제입니다.
이 문제를 해결하기 위해 위 코드에 사용한 var remainCount by MySynchronize(0)를 iOS의 Dispatch Group으로 아래와 같이 확장하도록 하겠습니다.
class DispatchGroup {
private var count = 0
private var runnable: (() -> Unit)? = null
init {
count = 0
}
@Synchronized
fun enter() {
count++
}
@Synchronized
fun leave() {
count--
notifyGroup()
}
fun notify(r: () -> Unit) {
runnable = r
notifyGroup()
}
private fun notifyGroup() {
if (count <= 0 && runnable != null) {
runnable!!()
}
}
}
이제 DispatchGroup을 아래와 같이 사용하면 됩니다.
val group = DispatchGroup()
group.enter()
MyNetworkModel.getList(offset: 0, limit: 20){ result ->
// 작업할 내용
group.leave()
}
group.enter()
MyNetworkModel.getInfo(myInfo: userId){ result ->
// 작업할 내용
group.leave()
}
group.notify {
// 완료 후 처리할 작업
}
이제 코드가 깔끔해지고 제 마음도 편안해졌습니다.