[Android/Compose] 제트팩 컴포즈에서의 액티비티 갯수, Side Effect 및 생명주기

Falco·2022년 10월 7일
0

Android

목록 보기
30/55

How are Android activities handled with Jetpack Compose and Compose Navigation?

기존에 Jetpack Navigation라이브러리를 사용하여 SAA로 개발을 진행하였다. 그렇다면 Compose를 사용할 때는 어떻게 진행하면 될까?

액티비티는 한개면 충분하다.

Compose 앱은 SAA를 사용하도록 디자인되어 있다.

여러개의 액티비나 프래그먼트를 setcontent를 사용하여 각각 추가할 수 있지만, 액티비티사이의 데이터 전달에 대해 유의해야 한다. 이러한 방식은 기존의 앱에 새로운 컴포즈 화면을 추가하는 등 오래된 방식이다.

컴포즈에서는 하나의 액티비티내에서 Compose Navigtaion을 사용하여 더 쉽고, 더 적은 코드로, 데이터 전송에 있어 더 나은 퍼포먼스를 제공한다.

화면마다 생명주기는 어떻게 관리하나요?

그전에 Side-Effect에 대해 알고가야 할 것 같다.
Side-Effect는 컴포저블 외부에서 발생하는 앱 상태의 변화를 말한다.
자신이 아닌 외부의 상태에 영향을 받는 것을 의미

이러한 외부효과를 관리하기위해 여러 함수들이 있는데

LaunchedEffect

@Composable
@NonRestartableComposable
@OptIn(InternalComposeApi::class)
fun LaunchedEffect(
    key1: Any?,
    key2: Any?,
    key3: Any?,
    block: suspend CoroutineScope.() -> Unit
) {
    val applyContext = currentComposer.applyCoroutineContext
    remember(key1, key2, key3) { LaunchedEffectImpl(applyContext, block) }
}

LaunchedEffect함수는 현재 화면에 컴포지션이 일어날 때 필요한 작업을 실행하는 데 사용한다.

또한 이는 현재 컴포저블에 바인딩된 코루틴 컨텍스트에서 실행된다. 즉, suspend 함수를 실행할 수 있으며 뷰 계층에서 뷰가 사라지면(컴포저블이 사라지면) 코루틴이 취소된다.

해당 key1,key2값을 기준값으로 두어 key가 바뀔 때만 suspend fun을 취소하고 재실행할 수 있다.

@Composable
fun MyScreen(
    state: UiState<List<Movie>>,
    scaffoldState: ScaffoldState = rememberScaffoldState()
) {
	
    if (state.hasError) {
        // `scaffoldState.snackbarHostState`가 바뀌면 
        // LaunchedEffect는 취소되고 재시작 된다.
        LaunchedEffect(scaffoldState.snackbarHostState) {
            // 스낵바를 보여주는 와중 코루틴이 캔슬되면 자동으로 사라진다.
            // state.hasError가 false라면 코루틴은 종료된다.
            // 
            scaffoldState.snackbarHostState.showSnackbar(
                message = "Error message",
                actionLabel = "Retry message"
            )
        }
    }

    Scaffold(scaffoldState = scaffoldState) {
        /* ... */
    }
}

rememberCoroutineScope

현재 Composable의 코루틴스콥을 참조하여 외부에서 실행할 수 있도록 한다.
컴포저블 외부에 있지만 컴포지션을 종료한 후 자동으로 취소되도록 범위가 지정된 코루틴을 실행하고 싶을 때 사용

Composable이 파괴될 때 같이 파괴된다.

@Composable
fun MoviesScreen(scaffoldState: ScaffoldState = rememberScaffoldState()) {
    // MoviesScreen의 라이프사이클을 가진 코루틴 스코프
    val scope = rememberCoroutineScope()

    Scaffold(scaffoldState = scaffoldState) {
        Column {
            Button(
                onClick = {
                    // Create a new coroutine in the event handler to show a snackbar
                    scope.launch {
                        scaffoldState.snackbarHostState.showSnackbar("Something happened!")
                    }
                }
            ) {
                Text("Press me")
            }
        }
    }
}

rememberUpdatedState

리컴포지션이 재실행 되지 않아도 되는 State를 정의한다.

produceState : Compose State가 아닌 것을 Compose의 State로 변환한다.

DisposableEffect : 정리가 필요한 효과

키가 변경되거나 컴포저블을 종료한 후 정리해야 하는 부수적인 작업을 수행한다.


Using rememberCoroutineScope() vs LaunchedEffect

LaunchedEffect는 컴포저블이 처음 컴포지션되거나 리컴포지션이 될 때, key 값이 변경될 때 수행할 작업을 수행한다. 예를들어 ViewModel로 부터 데이터요청하기, 초기 애니메이션 실행하기 등등..
rememberCoroutineScope는 코루틴 스콥을 저장하여 특정 코드에서 suspend함수를 실행할 수 있게 해준다.

rememberCoroutineScope는 컴포지션이 일어나도 코루틴 스코프에 대한 참조를 유지한다.(LaunchedEffect는 유지하지 않고 Cancel되고 다시 실행됨) 주어진 Composable이 완전히 삭제됬을 때만 코루틴이 멈춘다.
예를들어 A -> B -> C 순서대로 컴포저블을 생성한다고 했을 때, C에서 rememberCoroutineScope을 실행한다면 C가 삭제됬을 때 코루틴은 자동으로 캔슬된다. 하지만 A에서 rememberCoroutineScrope을 실행한다면 C가 삭제되어도 코루틴은 계속 돌아간다.(A가 살아있기 때문에)

profile
강단있는 개발자가 되기위하여

0개의 댓글