[Android/Kotlin] CoroutineContext이 구성요소들을 추가하는 방법
Android/Kotlin

[Android/Kotlin] CoroutineContext이 구성요소들을 추가하는 방법


CoroutineScope 변수를 만들 때, Job, CoroutineExceptionHandler, Dispatchers 등을 더하기 연산으로 합쳐서 만들어내곤 합니다.
이것이 어떻게 가능한 것인지 알아봅시다.

 

Coroutine에 배정할 CoroutineContext 변수를 생성할 때, + (덧셈) 연산자로 원소들을 합치고는 합니다

 

1
2
3
4
5
6
7
open class ExampleViewModel: ViewModel() {
    protected val coroutineExceptionHanlder = CoroutineExceptionHandler { _, throwable ->
        throwable.printStackTrace()
    }
 
    protected val ioDispatchers = Dispatchers.IO + coroutineExceptionHanlder
}

 

그렇다면 어떻게 + 연산자로 DispatchersCoroutineExceptionHandler가 추가될 수 있을까요?

이유는 CoroutineContext 내에서 plus operator fun를 구현하고 있기 때문입니다.

신기한 것은 plus 함수 내에서 plus 연산을 하고 있지는 않고 minusKey만 하고 있는 모습입니다.

minusKey라는 것은, CombinedContext 내에서 원소들의 결합을 하기전에 같은 Element 들이 있다면 제거해주는 역할을 하는 함수입니다.

또한 fold 라는 함수를 쓰지만 이는 plus 바로 위에 있는 함수며 특별한 기능은 없고

inital로 들어온 클래스와 Element라는 클래스를 Lambda Scope 내에 반환할 뿐 입니다.

 

그런데 Element 라는 클래스는 뭘까요?

 

이는 사실 위에 사용한 Dispatchers, CoroutineException의 가장 최상위 부모 클래스입니다

 

Element

ㄴAbstractCoroutineContextElement

   ㄴCoroutineDispatchers

       ㄴ Dispatchers

 

Element

ㄴAbstractCoroutineContextElement

   ㄴCoroutineExceptionHandler

 

 

그리고 ElementCoroutineContext 내에 구현되어 있는 Interface 입니다.

 

1
2
3
4
5
6
7
8
9
10
@SinceKotlin("1.3")
public interface CoroutineContext {
    ... 중략 ...
    /**
     * An element of the [CoroutineContext]. An element of the coroutine context is a singleton context by itself.
     */
    public interface Element : CoroutineContext {
        ... 중략 ...
    }
}

 

어렵게 빙빙 돌아왔지만, 결국 Element를 상속한 클래스는 CoroutineContext의 원소 역할을 하고 있다는 것으로 보면 됩니다.

 

즉 지금까지 내용을 정리하자면 CoroutineContext에 원소들을 할당하기 위해, 우선적으로 중복되는 Element들을 제거한 상황입니다.

 

 

 

이제 그럼 실질적으로 원소들을 합치는 내용이 있을 법한 CombinedContext에 대하여 살펴볼 차례입니다.

 

CombinedContext 생성자와 상속 관계는 아래와 같습니다.

주석부터 읽어보면, 이 클래스는 숨겨져있고, left-biased list(좌편향 리스트(?))라서 Plus가 자연적으로 작동한다.

는 내용입니다.

left-biased list가 정확히 무슨 뜻인지 모르겠습니다.

그래서 소스를 보면 아래와 같이 되어 있습니다.

 

CombinedContext의 left에 CombinedContext를 중첩시켜 CoroutineContext를 완성해가는 모습이고,

get의 경우 중첩해있는 CombinedContext를 까보며 반환하는 모습입니다.

이 때 Element가 있을 경우 바로 반환하고 아닐 경우는 left에 있는 CoroutineContext를 반환하는 처리를 합니다.

 

분석이 어렵지만.. 정리해보면

 

CombinedContext는 생성자 왼쪽에 CoroutineContext를, 오른쪽에는 Element를 받아 사용하며

이를 합칠 때는 CombinedContext 또한 CoroutineContext이니, 이를 왼쪽에 중첩하는 방식으로 저장한다는 느낌인 것 같습니다.

 

이를 그림으로 나타내보면

Element를 포함한 CombinedContext 를 중첩하는 방식이라고 생각됩니다. 

이제야 left-biased list가 무엇인지도 이해가 가긴 합니다.

 

쉽게 정리하자면 위의 방식으로 원소들이 합쳐져 CoroutineContext가 완성되는 것 입니다.

 

 

 

더 정확한 내용을 아신다면, 댓글 부탁드립니다 ^^

 

감사합니다