본문 바로가기

안드로이드

Compose 성능 최적화 (Donut hole, 도넛홀)

반응형

https://developer.android.com/jetpack/compose/performance/bestpractices?hl=ko#defer-reads 

 

권장사항 준수  |  Jetpack Compose  |  Android Developers

권장사항 준수 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 발생할 수 있는 일반적인 Compose 실수가 몇 가지 있습니다. 이러한 실수로 인해 코드가 잘 실행

developer.android.com

안드로이드 디벨로퍼 가이드에서 가장 중요한 개념은 "읽기 연기" 라고 보여집니다.

성능 최적화를 하려면 리컴포지션(recomposition)을 최소화 해야합니다. Composition Scope 안에서 Stable 한 변수가 있으면 그것이 바뀔 때마다 해당 컴포지션이 리컴포지션이 일어납니다. 따라서 Composition Scope 를 여러겹이라면 최상단이 아닌 자식 Scope 에서 해당 변수를 읽는 것이 가장 바람직합니다. 이는 도넛홀이라고 부르기도 합니다.

@Composable
fun SnackDetail() {
    // ...

    Box(Modifier.fillMaxSize()) { // Recomposition Scope Start
        val scroll = rememberScrollState(0)
        // ...
        Title(snack, scroll.value) // .value 라고 된 순간 해당 부분에서 리콤포지션이 일어난다.
        // ...
    } // Recomposition Scope End
}

@Composable
private fun Title(snack: Snack, scroll: Int) {
    // ...
    val offset = with(LocalDensity.current) { scroll.toDp() }

    Column(
        modifier = Modifier
            .offset(y = offset)
    ) {
        // ...
    }
}

위 코드에서 보면 scroll.value 를 읽으면 Recomposition Scope 는 SnackDetail 이 된다.

@Composable
fun SnackDetail() {
    // ...

    Box(Modifier.fillMaxSize()) { // Recomposition Scope Start
        val scroll = rememberScrollState(0)
        // ...
        Title(snack) { scroll.value }
        // ...
    } // Recomposition Scope End
}

@Composable
private fun Title(snack: Snack, scrollProvider: () -> Int) {
    // ...
    val offset = with(LocalDensity.current) { scrollProvider().toDp() } // 변경점
    Column(
        modifier = Modifier
            .offset(y = offset)
    ) {
    // ...
    }
}

위 코드에서 보면 변경점은 SnackDetail 에서 직접 scroll.value를 하지않고 scroll.value 하는 람다를 인자로 전달해준 것이다.

그렇게 되므로 scroll.value 의 scope는 Title 영역으로 들어간다. 따라서 parent 의 Scope는 Recoposition을 skip하게된다.

그냥 재사용된다는 의미다. 위 코드에서 리콤포지션 범위는 Title 안이다.

해당 내용에 대한 테스트는 Android Studio 에서 LayoutInspector 에 의해서 확인할 수 있다.

팀 내에서 이 Studio의 count 기능이 정확한가? 정확하지 않은가? 에 대한 논의가 있었으나 저는 정확한 편이라고 판단합니다.
로그로 확인하는 것은 오히려 혼란만 가중시킬 뿐... 물론 로그로도 공부해보면 원리에 대한 이해는 더 깊이 있게 할 수 있습니다.

뒤 예제에 나오는 내용들도 "지연 읽기"에 대한 설명들이다.

- offset(dx, dy)를 사용하지않고 offset {} 람다를 사용하는 것
- drawbehind() 를 이용해 그리기 단계에서만 색상을 읽는 방법

반응형

'안드로이드' 카테고리의 다른 글

Android의 Touch Event 전달  (0) 2023.01.25
Android 인터뷰 20선 - 2  (0) 2023.01.23
안드로이드 인터뷰 면접 질문 20선! - 1  (0) 2022.09.18
Android, Compose 왜 생겼을까?  (0) 2022.07.29
AttributeSet  (0) 2022.07.09