[Android] Compose, Stateful, Stateless, UDF

elliot·2021년 9월 5일
0

Android

목록 보기
5/7
post-thumbnail

Compose

설명

  1. Compose는 선언형 UI 프레임워크이다.
  2. 처음부터 화면 전체를 개념적으로 재생성한 후 필요한 변경사항만 적용하는 방식으로 작동한다.
  3. 특정 시점에 UI의 어떤 부분을 다시 그려야 하는지를 지능적으로 선택한다.

Composable

// Composable 함수는 데이터를 받아서 UI요소로 Emit하는 함수
@Composable
  fun Greeting(name:String){
     Text("hello World")
  }

Composable 내부 흐름

  1. 앱 로직은 최상위의 composable 함수에 데이터를 제공한다.
  2. 다른 composable함수를 호출해서 UI를 형성하고 적절한 데이터를
    해당 컴포저블 및 계층 구조 아래로 전달한다.

  1. 사용자가 UI와 상호 작용할 때 UI는 onClick과 같은 이벤트를 발생시킨다.
  2. 이 이벤트를 앱 로직에 전달하여 앱의 상태를 변경해야한다.
  3. 상태가 변경되면 composable 함수는 새 데이터와 함께 다시 호출된다.
  4. 이렇게 하면 UI 요소가 다시 그려진다.
  • 이 프로세스를 재구성(Recomposition) 이라고 한다.

Remember

  1. remember에 의해 계산된 값은 초기 컴포지션 중에 컴포지션에 저장된다.
  2. 저장된 값은 리컴포지션(재구성) 중에 반환된다.
// 아래코드 실행시 화면의 텍스트 박스에 글을 적어도 화면에 반영되지 않는다.
@Composable
fun HelloContent() {
   Column(modifier = Modifier.padding(16.dp)) {
       Text(
           text = "Hello!",
           modifier = Modifier.padding(bottom = 8.dp),
           style = MaterialTheme.typography.h5
       )
       OutlinedTextField(
           value = "",
           onValueChange = { },
           label = { Text("Name") }
       )
   }
}
//아래코드 실행시 화면의 텍스트 박스에 글을 적으면 화면에 실시간으로 반영된다.
@Composable
fun HelloContent() {
   Column(modifier = Modifier.padding(16.dp)) {
       var name by remember { mutableStateOf("") }
       Text(
           text = "Hello",
           modifier = Modifier.padding(bottom = 8.dp),
           style = MaterialTheme.typography.h5
       )
       OutlinedTextField(
           value = name,
           onValueChange = { name = it },
           label = { Text("Name") }
       )
   }
}
  1. Composable함수를 업데이트를 하려면 by remember { mutableStateOf() }를 사용해야한다.
  2. OutlinedTextField의 상태를 나타내는 값을 전달한다. (value)
  3. OutlinedTextField의 값이 변경될 때 상태를 업데이트하는 코드를 추가한다 (onValueChance)

Stateful

  • remember를 사용하여 객체를 저장하는 컴포저블은 내부 상태를 생성하여 컴포저블을 스테이트풀(Stateful)로 만든다.
  • Stateful Composable은 내부상태를 가진다.
  • 호출자가 상태를 제어할 필요가 없고 상태를 직접 관리하지 않아도 상태를 사용할 수 있는 경우에 유용하다.
  • 재사용 가능성이 적고 테스트하기가 더 어려운 경향이있다.

Stateless

  • Stateless Composable은 상태를 갖지 않는다.
  • Stateless 를 달성하는 방법은 State Hoisting을 사용하는 것이다.

State Hoisting

  • 구성요소를 스테이트리스(Stateless)로 만들기 위해 상태를 트리 위로 옮기는 패턴이다.
  • 이 패턴이 컴포저블에 적용되는 경우 컴포저블에 매개변수 2개가 추가될 때가 많다.
    1.value: T: 표시할 현재 값
    2.onValueChange: (T) -> Unit: T가 제안된 새 값인 경우 값을 변경하도록 요청하는 이벤트
@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }

    HelloContent(name = name, onNameChange = { name = it })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.h5
        )
        OutlinedTextField(
            value = name,
            onValueChange = onNameChange,
            label = { Text("Name") }
        )
    }
}
  • 위 예에서 HelloContent에서 name과 onValueChange를 추출한 다음, 이 항목을 트리 상단에 HelloContent를 호출하는 HelloScreen Composable로 옮긴다.
  • HelloContent에서 상태를 끌어올리면 더 쉽게 Composable을 추론하고 여러 상황에서 재사용하며 테스트할 수 있다.
  • HelloContent는 상태의 저장 방식과 분리된다. 분리된다는 것은 HelloScreen을 수정하거나
    교체할 경우 HelloContent의 구현 방식을 변경할 필요가 없다는 의미이다.

Unidirectional Data Flow(단방향 데이터 흐름)

설명

  • 상태가 내려가고 이벤트가 올라가는 패턴을 단방향 데이터 흐름이라고 한다.
  • 위의 경우 상태는 HelloScreen에서 HelloContent로 내려가고, 이벤트는 HelloContent에서 HelloScreen으로 올라간다.
  • 단방향 데이터 흐름을 따르면 UI에 상태를 표시하는 Composable과 상태를 저장하고 변경하는 앱 부분을 서로 분리할 수 있다.

ViewModel 추가

class HelloViewModel : ViewModel() {
    
    private val _name = MutableLiveData("")
    val name: LiveData<String> = _name
    
    fun onNameChange(newName: String) {
        _name.value = newName
    }
}

@Composable
fun HelloScreen(helloViewModel: HelloViewModel = viewModel()) {
    val name: String by helloViewModel.name.observeAsState("")
    HelloContent(name = name, onNameChange = { helloViewModel.onNameChange(it) })
}

@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    Column(modifier = Modifier.padding(16.dp)) {
        Text(
            text = "Hello, $name",
            modifier = Modifier.padding(bottom = 8.dp),
            style = MaterialTheme.typography.h5
        )
        OutlinedTextField(
            value = name,
            onValueChange = onNameChange,
            label = { Text("Name") }
        )
    }
}
  • Compose에서는 상태를 보존하기 위해 MutableState<T>를 사용할 필요가 없다.
  • observeAsStateLiveData<T>를 관찰하고, LiveData가 변경될 때마다 업데이트되는 State<T> 객체를 반환한다.
  • State<T>는 Compose가 직접 사용할 수 있는 관찰 가능한 유형이다.
  • observeAsState는 컴포지션에 있는 동안에만 LiveData를 관찰한다.
profile
성장하는 개발자

0개의 댓글