[Jetpack Compose] 3. Architecture and state(2) #Side Effects #Saver

0

Jetpack Compose

목록 보기
11/11
post-thumbnail
post-custom-banner

[Jetpack Compose] 3. Architecture and state(2) #Side Effects #Saver

📌참고자료

Advanced State and Side Effects in Jetpack Compose

📌참고자료

  • Side Effect in Compose:
    a change to the state of the app that happens outside the scope of a composable function
  • composables should ideally be side-effect free
    -> composable의 생명주기 & 특징 때문
    • unpredictable recompositions
    • executing recompositions in different orders
    • recompositions can be discarded
  • sometimes, side-effects are necessary
    • ex. triggering on-off event (show snackbars, navigate screens)
    • these actions should be called from a controlled environment
      -> use Effect API to execute side-effects in a predictable manner
  • effect:
    a composable function that doesn't emit UI and causes side effects to run when composition completes

LaunchedEffect

  • run suspend functions in scope of a composable
  • LaunchedEffect is a composable function
    -> can only be used in other composable functions
  • LaunchedEffect enters composition -> launches a coroutine
  • LaunchedEffect leaves composition -> cancels the coroutine
  • LaunchedEffect recomposed with different keys -> cancel existing coroutine & launch new coroutine

rememberUpdatedState

  • reference a value in an effect that shouldn't restart if the value changes
@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
    mutableStateOf(newValue)
}.apply { value = newValue }
@Composable
fun TimerExample(timer: Timer) {
    val currentTime by timer.currentTime.collectAsState()
    val onTimeout = rememberUpdatedState(newValue = { 
        // Handle timeout
    })
    LaunchedEffect(currentTime) {
        if (currentTime >= TIMEOUT_DURATION) {
            onTimeout.value()
        }
    }
    Text(text = "Time: $currentTime")
}

rememberCoroutineScope

  • launch a coroutine outside of a composable, but scoped with the composable
    -> automatically canceled once it leaves the composition
  • rememberCoroutineScope는 자신을 호출한 Composition의 CoroutineScope를 반환하는 composable function

DisposableEffect

  • effects that require cleanup
  • 블록 맨 마지막에 onDispose 절 반드시 포함해야
    • 빈 블록의 onDispose는 좋은 practice가 아님 -> 더 적절한 다른 effect 사용하기

SideEffect

  • share Compose state with non-Compose code
  • 성공적인 recomposition이 실행돨 때 마다 effect가 실행되도록 보장됨
    = recomposition의 성공이 보장되지 않는 상태에서 effect 실행되지 X

produceState

  • convert non-Compose state into Compose state
    • ex. external subscription-driven state(ex. Flow, LiveData, RxJava)
  • can also be used to observe non-suspending sources of data
  • produceState enters composition -> producer is launched
  • produceState leaves composition -> producer is cancelled
  • ViewModel에서 UI state를 관리하는 것이 권장되지만,
    UI state이 매우 간단하다면 composable 내부에서 produceState을 사용하는 것이 best alternative

snapshotFlow

  • convert Compose's state object into cold Flow
  • snapshotFlow 블록에 터미널 연산자(collect, collectLast, 등) 불림
    -> 블록 내부 State object들의 값을 emit
  • snapshotFlow 블록 내부 State object 값 변경됨
    -> Flow will emit new value to its collector

derivedStateOf

  • convert one or multiple state objects into another state
  • use when inputs to a composable are changing more often than you need to recompose
  • derivedStateOf creates new Compose state object
    -> to execute recomposition only when condition toggles
  • expensive

  • Saver:
    describes how the object of Original class can be simplified & converted into something Saveable
    • restore(value: Saveable): Original?
    • SaverScope.save(value: Original): Saveable?
  • Savable types:
    • defined by SaveableStateRegistry
    • by default, Bundle 클래스에 저장 가능한 타입은 다 저장 가능
  • SaveableStateRegistry interface
    • canBeSaved(value: Any): Boolean
      value가 해당 Registry에 저장 가능한지 반환
    • consumeRestored(key: String): Any?
      key에 대해 저장된 값 반환
    • performSave(): Map<String, List<Any?>>
      executes all the registered value providers -> map으로 combine하여 반환
    • registerProvider(key: String, valueProvider: () -> Any):SaveableStateRegistry.Entry
      register value provider
profile
Be able to be vulnerable, in search of truth
post-custom-banner

0개의 댓글