본문 바로가기

카테고리 없음

[Android] Composable과 suspend의 유사성

코트린 suspend method는 suspend method 안에서 부를 수 있다.

이는 코틀린 코드를 자바 코드로 바꾸어 보면 이유를 유추해 볼 수 있다.

 

suspend fun a() {
    b()
}

suspend fun b() {

}

 

위 코드를 자바 코드로 바꾸어 보면

@Nullable
public static final Object a(@NotNull Continuation $completion) {
   Object var10000 = b($completion);
   return var10000 == IntrinsicsKt.getCOROUTINE_SUSPENDED() ? var10000 : Unit.INSTANCE;
}

@Nullable
public static final Object b(@NotNull Continuation $completion) {
   return Unit.INSTANCE;
}

 

이렇듯 Continuation에서 context를 통해 코틀린 런타임이 필요로 하는

정보를 전달하면서 전파해 나아가는 방식이다.

 

그렇다면 컴포저블은 어떤 형태를 띄고 있을 것인가

@Composable
fun a() {
    b()
}
@Composable
fun b() {
    
}

 

를 바꾸어 보면 다음과 같다.

fun a($composer: Composer<*>) {
    $composer.start(123)
    b($composer)
    $composer.end()
}

fun b($composer) {
    '''
}

 

컴포저블도 마찬가지로 composer를 앞으로 전파해 나아가는

위에서 확인한 suspend와 마찬가지의 형태를 띄고 있다.

 

따라서, Composable도 Composable내부에서만 사용가능한 것이다.

 

그런데, 아래와 같은 코드는 어떻게 가능한 것인가?

@Composable
fun a(bs: MutableList<Int>) {
    bs.forEach {
        b()
    }
}
@Composable
fun b() {

}

 

이렇듯 forEach의 람다에 컴포저블을 불러도 에러 메세지를 보이지 않는다.

 

이것은 forEach를 볼 필요가 있다.

public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
    for (element in this) action(element)
}

 

그렇다 다른 Collection 함수들처럼 inline으로 정의가 되어있다.

inline은 컴파일러가 호출 함수의 코드를 직접 복사에서 붙여 넣기 때문에 

위의 b컴포저블은 사실상 a컴포저블에서 불리게 된 것이다.

 

이렇듯 컴포저블에서 코틀린 로직의 사용이 필요할 때는 inline method를 사용함으로서 해결할 수 있다.