봄날은 갔다. 이제 그 정신으로 공부하자

android 개발자를 위한 Dispatch Group 본문

android Tip

android 개발자를 위한 Dispatch Group

길재의 그 정신으로 공부하자 2022. 12. 1. 11:11

앞선 글(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 {
	// 완료 후 처리할 작업
}

 

이제 코드가 깔끔해지고 마음도 편안해졌습니다.

Comments