ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] Compose 에 대해 알아보자 part.1 개요
    Android 2021. 10. 24. 14:41

     

    안녕, 형들~ 🙌

    이번 문서는 Android-Compose 공식문서 기반으로 작성하였고, 해당 문서에서 아래내용을 모두 확인할 수 있어~

    개요

    Jetpack Compose는 최근 안드로이드 진영에서 밀고 있는 선언형 UI Toolkit 인데, Swift 에 SwiftUI(스유) 가 있다면 Android 에는 Compose 가 있다고 말할 수 있어.
    Compose는 프런트엔드 뷰를 명령형(imperatively)으로 변형하지 않고도 앱 UI를 렌더링할 수 있게 하는 선언형(declarative) API를 제공하여 앱 UI를 더 쉽게 작성하고 유지관리할 수 있도록 도와주는데, XML 에 익숙한 개발자라면 compose 스타일에 익숙해지는데 좀 걸릴 수 있을 것 같아.

     

    The declarative programming paradigm (선언형 프로그래밍 패러다임)

    기본적으로 Android 에서는 사용자와의 상호작용 등을 이유로 인해 앱의 상태가 변경되면, 현재 데이터를 표시하기 위해 UI 계층 구조를 업데이트 하는데,
    여기서 업데이트를 하기 위한 뷰 계층 구조는 트리 형태로 표시할 수 있고,
    UI를 업데이트하는 가장 일반적인 방법은 findViewById()와 같은 함수를 사용하여 해당 트리를 탐색한 후, button.setText(String), container.addChild(View) 또는 img.setImageBitmap(Bitmap)과 같은 메서드를 호출하여 노드를 변경하는 것이야.

    이러한 메서드를 통해 위젯의 내부 상태를 변경할 수 있어.

     

    즉, 뷰의 상태에 대한 업데이트는 아래와 같은 순서로 진행 돼어어어~

    1. 뷰 계층 구조 탐색
    2. 위젯 내부의 메서드 호출
    3. 상태 변경

    이러한 방식은 아래와 같은 단점이 존재하는데,

    • 뷰를 수동으로 조작하면 오류가 발생하기 쉽다.
    • 데이터를 여러 위치에서 렌더링한다면 데이터를 표시하는 뷰 중 하나를 업데이트하는 것을 잊기 쉽다.
    • 여러 업데이트를 통해서 충돌이 발생한 경우, 상태에 대한 트랙킹이 어렵다. (예를 들어 업데이트가 UI에서 방금 삭제된 노드의 값을 설정하려고 할 수 있다)

    즉, 일반적으로 업데이트가 필요한 뷰의 수가 많을수록 소프트웨어 유지관리 복잡성이 증가하게 돼

     

    지난 몇 년에 걸쳐 업계 전반에서는 선언형 UI 모델로 전환하기 시작했으며, 이에 따라 사용자 인터페이스 빌드 및 업데이트와 관련된 엔지니어링이 크게 간소화되었는데, 
    이 기법은 처음부터 화면 전체를 개념적으로 재생성(recomposition)한 후 필요한 변경사항만 적용하는 방식으로 작동 돼


    이러한 접근 방식은 스테이트풀(Stateful) 뷰 계층 구조를 수동으로 업데이트할 때의 복잡성을 방지할 수 있어.

     

    다만 화면 전체를 재생성하는 데 있어 한 가지 문제는 시간, 컴퓨팅 성능 및 배터리 사용량 측면에서 잠재적으로 비용이 많이 든다는 것이고,
    Compose 에서는 이 비용을 줄이기 위해 특정 시점에 UI의 어떤 부분을 다시 그려야 하는지를 지능적으로 선택한고 있어.

     

    A simple composable function (간단한 composable 함수)

    그럼 간단한 Composable 함수 사용에 대해서 알아볼까~? 🤩

     

    Compose를 사용하면 데이터를 받아서 UI 요소를 내보내는 composable 함수 집합을 정의하여 UI 를 빌드할 수 있어.


    예를들어, 아래처럼 Greeting 위젯으로, String을 받아서 인사말 메시지를 표시하는 Text 위젯을 내보낼 수 있는데,

     

    @Composable
    fun Greeting(name: String) 
    { 
        Text("Hello $name") 
    }

    위 예에 관해 몇 가지 주목할 만한 참고 사항:

    • 함수는 @Composable annotation 으로 지정해주어야 한다. 모든 Compose 에 사용되는 함수에는 이 annotation 이 있어야 한다.
    • @Composable annotation 을 통해 해당 함수가 데이터를 UI로 변환하기 위한 함수라는 것을 Compose 컴파일러에 알릴 수 있다.
    • 함수는 데이터를 받는다. 함수는 매개변수를 받을 수 있으며 이 매개변수를 통해 앱 로직이 UI를 형성할 수 있다. (위 예에서 Greeting 위젯은 String 을 받아서 이름을 표시하고 있다)
    • 텍스트 UI 요소를 생성하는 Text() 함수를 호출해서 UI에 텍스트를 표시한다.
    • 함수는 아무것도 반환하지 않는다. UI를 내보내는 Compose 함수는 UI 위젯을 구성하는 대신 원하는 화면 상태를 나타내주므로 아무것도 반환할 필요가 없다.
    • 이 함수는 빠르고 멱등원이며 부작용이 없다.
      • 함수는 동일한 인수로 여러 번 호출될 때 동일한 방식으로 작동하며, 전역 변수 또는 random() 호출과 같은 다른 값을 사용하지 않는다.
      • 함수는 속성 또는 전역 변수 수정과 같은 부작용(side-effects) 없이 UI를 형성합니다.

     

    The declarative paradigm shift (선언형 패러다임 전환)

    많은 명령형 객체 지향 UI Toolkit를 사용하여 위젯의 트리를 인스턴스화함으로써 UI를 초기화하는데,
    흔히 안드로이드에서는 XML 레이아웃 파일을 통해, 각 위젯은 자체의 내부 상태를 유지하고 앱 로직이 위젯과 상호작용할 수 있도록 하는 getter 및 setter 메서드를 노출시켜줘서 개발자들이 원하는 동작을 시킬 수 있도록 만들어줘.

     

    Compose의 선언형 접근 방식에서 위젯은 비교적 스테이트리스(Stateless) 상태이며 getter 및 setter 함수를 노출하지 않는데, (사실상 위젯은 객체로 노출되지 않는다)
    동일한 composable 함수를 다른 인수로 호출하여 UI를 업데이트할 수 있고, 이렇게 하면 앱 아키텍처 가이드에 설명된 대로 ViewModel과 같은 아키텍처 패턴에 상태를 쉽게 제공할 수 있어.

    data

    앱 로직은 최상위의 composable 함수에 데이터를 제공하고, 그러면 함수는 데이터를 사용하여 다른 composable을 호출함으로써 UI를 만든 후 적절한 데이터를 해당 composable 및 계층 구조 아래로 전달시켜 줘.

    상위 수준 객체부터 하위 요소까지 Compose UI의 데이터 흐름을 보여주는 그림

    event

    사용자가 UI와 상호작용할 때 UI는 onClick과 같은 이벤트를 발생시켰을 때, 이러한 이벤트를 앱 로직에 전달하여 앱의 상태를 변경해야 하는데, 이 때 상태가 변경되면 composable 함수는 새 데이터와 함께 다시 호출 돼.

    이렇게 하면 UI 요소가 다시 그려지게 되고, 이 프로세스를 recomposition (재구성) 이라고 해.


    사용자가 UI 요소와 상호작용하며 이에 따라 이벤트가 트리거되고 앱 로직이 이벤트에 응답하면서, composable 함수가 필요한 경우 새 매개변수를 사용하여 자동으로 다시 호출돼.

    앱 로직에 의해 처리되는 이벤트를 트리거하여 UI 요소가 상호작용에 어떻게 응답하는지 보여주는 그림

     

    Dynamic Content (동적 콘텐츠)

    composable 함수는 XML이 아닌 Kotlin으로 작성되기 때문에 다른 Kotlin 코드와 마찬가지로 동적일 수 있어.

     

    @Composable
    fun Greeting(names: List<String>) {
        for (name in names) { 
            Text("Hello $name") 
        } 
    }

     

    위 예시에서 함수는 이름 목록을 받아서 각 사용자에 대한 인사말을 생성하는데, composable 은 Kotlin 으로 작성되므로, if 문을 사용하여 특정 UI 요소를 표시할지 여부를 결정할 수 있고, 루프를 사용할 수도 있고, 다른 함수를 호출할 수도 있어.
    즉, 기본 언어의 유연성을 완전히 활용할 수 있다는 뜻이고, 이러한 성능과 유연성은 Jetpack Compose의 주요 이점 중 하나야

     

     

    일단 여기까지해서 compose 의 개요에 대해서 알아봤어.

    다음에는 compose 에서 중요 개념중 하나인 recomposition(재구성) 에 대해서 알아보려고 해~

     

    확실히 선언형 UI Toolkit 은 요즘 대세가 되어가고 있는 것 같고,

    때문에, 장단점 과 제약사항등 개념을 확실히 잡고 가는게 중요한 것 같아!!

     

    다들 힘내자고~ 아자아자!! 👋

     

     

Designed by Tistory.