코딩

[코루틴 (14)] Compose Navigation + 코루틴 취소/재시작 사례

Eastpark 2025. 2. 18. 22:05
728x90
반응형

지난 13편에서는 Jetpack Compose코루틴, Flow가 결합해 선언형 UI에서 비동기 처리를 매끄럽게 다루는 방법을 살펴보았습니다. 이번 글에서는 Compose Navigation 시나리오에서 화면 전환 중에 코루틴이 취소되고, 새 화면이 나타나면 코루틴이 재시작되는 사례를 구체적으로 소개하려 합니다.

 

핵심 키워드

Compose Navigation

코루틴 취소 & 재시작

Navigation Graph

NavController

Lifecycle


1. Compose Navigation과 화면 전환

 

1.1 개요

 

Compose Navigation은 Jetpack Compose에서 여러 화면(Screen)을 전환할 때 사용하는 라이브러리입니다. NavHostNavController를 설정해 route별로 Composable을 등록하고, navController.navigate("detail") 같은 방식으로 화면을 전환합니다.

@Composable
fun MyAppNavHost(navController: NavHostController) {
    NavHost(navController, startDestination = "home") {
        composable("home") { HomeScreen(navController) }
        composable("detail") { DetailScreen(navController) }
    }
}

HomeScreenDetailScreen으로 이동 시, HomeScreen은 Lifecycle이 STOPPED → DESTROYED 상태가 될 수 있습니다. 이 과정에서 HomeScreen 내 코루틴은 자동으로 취소될 수 있습니다.


2. 코루틴 취소와 재시작 메커니즘

 

2.1 Composable Lifecycle

 

Compose Navigation에서 화면 A → 화면 B로 이동하면, 기본적으로 화면 A(Composable) 상태가 STOPPED 혹은 DESTROYED가 되어, 그에 연동된 CoroutineScope가 취소됩니다.

만약 화면 A에서 LaunchedEffectrememberCoroutineScope로 실행 중인 코루틴이 있다면, 화면이 사라질 때 취소(CancellationException)됩니다.

 

2.2 새 화면에서 코루틴 재시작

 

화면 B로 넘어가면 B Composable이 새로 LaunchedEffect, rememberCoroutineScope 등을 사용해 비동기 작업을 시작할 수 있습니다.

즉, 화면 전환을 기점으로 한 화면의 코루틴취소되고, 다음 화면에서 새 코루틴재시작되는 구조입니다.

이는 Structured Concurrency와 유사한 개념으로, 화면 단위의 스코프가 생명주기에 맞춰 생성·소멸된다고 볼 수 있습니다.

반응형

3. 예시: 화면 전환 중 네트워크 요청 중단

 

3.1 시나리오

 

1. 홈 화면(HomeScreen)에서 사용자 리스트를 가져오는 네트워크 요청을 수행 중

2. 사용자가 리스트를 다 받기 전에 DetailScreen으로 넘어감

3. HomeScreen이 사라질 때, “리스트 가져오기” 코루틴이 취소

4. DetailScreen에서는 새로운 네트워크 요청(예: 상세정보 가져오기)을 시작

 

3.2 코드 스케치

@Composable
fun HomeScreen(navController: NavController, viewModel: HomeViewModel = ...) {
    val uiState by viewModel.uiState.collectAsState()

    // 코루틴 예: 화면이 처음 보여지면 데이터 로드
    LaunchedEffect(Unit) {
        viewModel.loadUserList()
    }

    when (uiState) {
        is HomeUiState.Loading -> LoadingContent()
        is HomeUiState.Success -> UserListContent(
            userList = uiState.userList,
            onUserClick = { userId ->
                navController.navigate("detail/$userId")
            }
        )
        is HomeUiState.Error -> ErrorContent()
    }
}

DetailScreen에 진입하면 새 코루틴(viewModel.loadDetail())이 시작되어, 이전 화면의 코루틴과 무관하게 데이터를 받습니다.


4. 사용자 피드백(Progress, Cancel 버튼) 시나리오

 

4.1 Loading 표시와 사용자 취소

 

Compose Navigation 구조에서 “화면 A에서 로딩 중”일 때, 사용자가 “뒤로가기”나 “다른 화면으로 navigate”를 누르면, “화면 A”가 곧 사라집니다.

결과: “화면 A” 코루틴이 취소 → “로딩”도 멈춤.

“화면 B”가 새로 표시되며, 필요한 경우 다른 코루틴이 시작.

 

4.2 명시적 취소 버튼

 

만약 “로딩 중 취소” 버튼을 화면에 두고, 사용자 클릭 시 해당 코루틴을 명시적으로 취소하고 싶다면, rememberCoroutineScope를 통해 코루틴에 접근하거나, ViewModel에서 Job을 관리해 job.cancel()을 호출할 수 있습니다.

화면 전환을 동반할 경우, Compose Navigation이 화면 A를 제거하면, ViewModel 스코프나 Composable 스코프 자체가 중단되므로 명시 취소가 불필요해질 수도 있습니다.

728x90

5. LifecycleOwner & Complex Navigation

 

5.1 Nested Graph 시나리오

 

Compose Navigation에서 Nested GraphBottom Nav처럼 여러 화면이 동시에 존재하는 구조라면, 모든 비활성 화면이 반드시 즉시 DESTROYED 상태가 되는 것은 아닐 수 있습니다(특히, keep state 옵션 등).

이러한 구조에선, one Composable이 단순히 “화면 전환” 이벤트만으로 취소되지 않을 수도 있습니다.

Lifecycle 상태를 확인하거나, Navigation을 어떻게 구성하는지에 따라 달라지므로, 중첩 구조에 대한 정확한 이해가 필요합니다.

 

5.2 “PopBackStack”과 코루틴 중단

 

navController.popBackStack()으로 이전 화면으로 돌아가는 시나리오에서도, 최상단 Composable이 사라질 때 해당 스코프가 취소됩니다.

새로 보여지는 화면이 이미 상태를 유지하고 있었다면, 그 화면의 코루틴 스코프는 여전히 활성 상태일 수 있습니다.


6. 요약: Compose Navigation + 코루틴 취소/재시작

 

1. 화면 전환 → 이전 Composable이 Lifecycle DESTROY → 이전 화면의 코루틴 자동 취소

 

2. 새 화면 진입LaunchedEffect or collectAsState 등으로 새 코루틴 실행

 

3. 중첩 Navigation / keep state 시, “사라지는” Lifecycle을 정확히 파악해야 올바른 취소/재시작 보장

 

4. 명시적 취소(버튼, 이벤트)도 ViewModel에서 job.cancel()로 가능. 화면을 떠나면 Composable Scope나 ViewModelScope 자체가 소멸될 수도 있음.


7. 마무리 및 시리즈 결론

 

이번 [14편]을 통해, Compose Navigation 시나리오에서 코루틴 취소 및 재시작이 어떻게 동작하는지 살펴보았습니다.

Composable이 Lifecycle DESTROYED가 되면, 해당 화면의 코루틴은 자동 취소

새로운 화면이 나타나면, LaunchedEffectcollectAsState 등으로 새 코루틴을 시작

이 로직 덕분에, 화면 전환에 따라 비동기 작업 흐름이 구조적으로 구분되어 유지보수성을 높일 수 있음


시리즈 전체 목차

0. 코루틴 탄생 배경과 기본 개념

1. 코루틴 기초(suspend, CoroutineScope, Dispatcher)

2. Structured Concurrency와 코루틴 스코프 관리

3. 예외 처리와 취소(Cancellation) 기법

4. 코루틴 채널(Channel)과 select

5. Flow 심화(Flow, StateFlow, SharedFlow)

6. 안드로이드 실무 적용(Retrofit, Room, ViewModel)

7. 동시성 문제 해결(Mutex, Semaphore)

8. 코루틴 테스트 & 디버깅 전략

9. 고급 퍼포먼스 최적화

10. WorkManager + 코루틴 연동

11. LifecycleScope & 안드로이드 생명주기 대응

12. Compose + 코루틴 + Flow 시너지

13. Compose Navigation + 코루틴 취소/재시작 사례

 

728x90
반응형