Compose의 State

2022. 3. 3. 15:55Android/AAC

반응형

- remember : 메모리에 composable의 상태를 저장할 수 있게 해주는 composable

  • val mutableState = remember { mutableStateOf(default) }
  • var value by remember { mutableStateOf(default) }
  • val (value, setValue) = remember { mutableStateOf(default) }

- rememberSaveable : 자동적으로 bundle() 형태의 저장을 통해 configuration change에 대응할 수 있는 composable

cf> bundle() 형태로 저장될 수 없는 객체 저장 방법

  • Parcelize
  • MapSaver
  • ListSaver

 

- 지원하는 observable types : State<T>의 형태로 변환해서 사용(ex> LiveData<T>.observeAsState())

  • LiveData
  • Flow
  • RxJava2

- state hoisting : 상태를 사용하는 composable의 공통 부모로 끌어올려 자식 composable을 stateless하게 만드는 방법

 

- state 범위에 따른 관리방법

  • Composables for simple UI element state management.
  • State holders for complex UI element state management. They own UI elements' state and UI logic.(다른 composable의 상태를 변경하는 경우에는 관리의 용이성을 위해 plain object로 state holder 사용 권장)
  • Architecture Components ViewModels as a special type of state holder in charge of providing access to the business logic and the screen or UI state.

cf> 필요하다면 plain object와 viewModel을 함께 State holder로 사용해도 되고, plain object는 viewModel 보다 수명이 짧아서 viewModel을 참조해도 됨.

private class ExampleState(
    val lazyListState: LazyListState,
    private val resources: Resources,
    private val expandedItems: List<Item> = emptyList()
) { ... }

@Composable
fun rememberExampleState(
    scaffoldState: ScaffoldState = rememberScaffoldState(),
    navController: NavHostController = rememberNavController(),
    resources: Resources = LocalContext.current.resources,
    /* ... */
) = remember(scaffoldState, navController, resources, /* ... */) {
    MyAppState(scaffoldState, navController, resources, /* ... */)
}

@Composable
fun ExampleScreen(viewModel: ExampleViewModel = viewModel()) {

    val uiState = viewModel.uiState
    val exampleState = rememberExampleState()

    LazyColumn(state = exampleState.lazyListState) {
        items(uiState.dataToDisplayOnScreen) { item ->
            if (exampleState.isExpandedItem(item) {
                ...
            }
            ...
        }
    }
}

 

- compositionLocal : param으로 state를 명시적으로 전이시키지 않고, 암시적으로 전달하는 방법(중간 composable은 알지 못해도 되는 값이 있을 때, 일일이 param으로 전달하지 않아도 state값을 참조할 수 있도록 하는 방법)

  • compositionLocalOf : Changing the value provided during recomposition invalidates only the content that reads its current value. -> 해당 값을 읽는 composable만 재구성
  • staticCompositionLocalOf : Unlike compositionLocalOf, reads of a staticCompositionLocalOf are not tracked by Compose. Changing the value causes the entirety of the content lambda where the CompositionLocal is provided to be recomposed, instead of just the places where the current value is read in the Composition. -> 해당 값 하위의 모든 composable 재구성
// AndroidCompositionLocals.android.kt
val LocalConfiguration = compositionLocalOf<Configuration>(
    neverEqualPolicy()
) {
    noLocalProvidedFor("LocalConfiguration")
}

/**
 * Provides a [Context] that can be used by Android applications.
 */
val LocalContext = staticCompositionLocalOf<Context> {
    noLocalProvidedFor("LocalContext")
}

internal val LocalImageVectorCache = staticCompositionLocalOf<ImageVectorCache> {
    noLocalProvidedFor("LocalImageVectorCache")
}

/**
 * The CompositionLocal containing the current [LifecycleOwner].
 */
val LocalLifecycleOwner = staticCompositionLocalOf<LifecycleOwner> {
    noLocalProvidedFor("LocalLifecycleOwner")
}

/**
 * The CompositionLocal containing the current [SavedStateRegistryOwner].
 */
val LocalSavedStateRegistryOwner = staticCompositionLocalOf<SavedStateRegistryOwner> {
    noLocalProvidedFor("LocalSavedStateRegistryOwner")
}

/**
 * The CompositionLocal containing the current Compose [View].
 */
val LocalView = staticCompositionLocalOf<View> {
    noLocalProvidedFor("LocalView")
}

 

- compositionLocalProvider : 하위 composable에 다른 값을 바인딩 시켜 기능을 수행하고 싶을 때 사용할 것

CompositionLocalProvider(
    LocalViewModelStoreOwner provides viewModelStoreOwner
) {
    FullMenu()
}

 

- compositonLocal의 대안 : compositionLocal은 국한된 state 사용을 위한 것이 아니고, 전역적으로 사용할 수 있는 값이라는 전제와 적절한 디폴트 값이 필요하다. 이를 지킬 수 없을 경우, 의존을 제거하는 방식으로는 아래의 방법을 이용한다.

  • param으로 명확한 state 전달
  • 제어의 역전(람다를 전달하고, 상위 composable에서 해당 내용을 처리하는 방식)
반응형

'Android > AAC' 카테고리의 다른 글

Kotlin Flow  (0) 2022.03.25
Kotlin Coroutine  (0) 2022.03.24
Compose 감잡기  (0) 2022.02.24
Jetpack - Compose  (0) 2021.10.28
Navigation  (1) 2021.08.13