본문 바로가기

개발 노트/Kotlin

[Android/Kotlin] StateFlow -> launchWhenCreated deprecated 해결

 

viewLifecycleOwner.lifecycleScope.launch {}를 사용하여 Fragment의 수명 주기에 연결된 코루틴을 사용하여 Flow를 사용하면, 이lifeCycle의 수명주기를 인식을 못한다는 단점이 있다

 

따라서 lifecycleScope.launchWhenCreated를 사용하여, lifeCycle의 수명주기를 인식하도록 해줄수있다

아래는 공식문서에 나온 설명이다

launchWhenStarted는 이 LifecycleCoroutineScope를 제어하는 ​​수명 주기가 최소한 Lifecycle.State.STARTED 상태일 때 지정된 블록을 시작하고 실행합니다.
반환된 Job은 Lifecycle이 폐기되면 취소됩니다.

 

즉, launchWhenCreated는 수명 주기가 STARTED 또는 RESUMED 상태가 아닐 때 코루틴 실행을 일시 중지한다. 이는 수명 주기가 다시 활성화될 때까지 코루틴이 작업을 수행하거나 리소스를 낭비하지 않음을 의미한다

이렇게 하면 불필요한 작업, 메모리 누수 또는 앱 충돌을 방지하는 데 도움이 될 수 있다

 

그치만 launchWhenCreated는 이제 deprecated되었다 -> 경우에따라 자원낭비로 이어질수도 있기 때문

(launchWhenStarted뿐만 아니라 다른 launchWhenX (launchWhenResumed, launchWhenCreated) 기능도 이제 더 이상 사용되지 않게되었다)

private fun observeViewModel(){
    lifecycleScope.launchWhenCreated {

        mapViewModel.regionSearch.collectLatest{
            Log.d("it_data", it.toString()) // SearchResponse 전체가져옴

            // 검색결과에 documents가 포함되어있으면(무조건 포함함), 그 documents값중 첫번쨰값을 가져옴
            it?.documents?.firstOrNull()?.let { document ->
                Log.d("documents__",document.toString()) // SearchDocumentsResponse의 첫번째값 가져옴
                setMapData(document)
            }
        }
    }
}

기존 코드

 

 

 

 

따라서 launchWhenCreated를 대체할기능으로 구글은 Lifecycle.repeatOnLifecycle API를 사용할 것을 권장한다

 

따라서 repeatOnLifecycle을 사용한 기본 예제를 봐보자

// lifecycleScope에서 새 코루틴을 만듭니다.
 lifecycleScope.launch { 
    // RepeatOnLifecycle은 수명 주기가 STARTED 상태에 있을 때마다 // 새 코루틴에서 블록을 시작하고 STOPPED일 때 취소합니다.
     RepeatOnLifecycle(Lifecycle.State.STARTED) { 
        // 값 수신을 시작합니다. 
        // 이는 수명 주기가 시작되고 
        수집이 중지될 때 발생합니다. // 수명 주기가 중지되면 수집이
         viewModel.dataFlow.collect { 
            // 수집된 값으로 일부 작업을 수행합니다.
         } 
    } 
}

repeatOnLifecycle 사용

 

 

repeatOnLifecycle은 권장되는 두가지 방법이 있는데

 

1. 단일흐름을 수집해야하는 경우는 flowWithLifecycle() 를 사용해서 구현할 수 있다

viewLifecycleOwner.lifecycleScope.launch { 
    myViewModel.getDataFlow() 
        .flowWithLifecycle(viewLifecycleOwner.lifecycle, Lifecycle.State.STARTED) 
        .collect { 
            // 수집된 값으로 일부 작업을 수행합니다.
         } 
}

단일흐름

 

 

2. 여러 흐름병렬로 수집해야 하는 경우 RepeatOnLifecycle을 사용해서 구현할 수 있다

lifecycleScope.launch { 
    repeatOnLifecycle(Lifecycle.State.STARTED) { 
        // 병렬로 여러 흐름을 수집합니다.
         launch { 
            myFlow1.collect { 
              // 수집된 값으로 일부 작업을 수행합니다.
             } 
        } 
        launch { 
            myFlow2.collect { 
              // 수집된 값으로 일부 작업을 수행합니다.
             } 
        } 
    } 
}

병렬

 

 

 

 

 

나는 아까 launchWhenCreated를 사용하여 구현했던 코드를

repeatOnLifecycle를 사용해서 수정해봤다

구현해야하는 사항은 단일흐름이기 때문에 flowWithLifecycle()를 사용해서 수정해주었다!!

private fun observeViewModel(){
    viewLifecycleOwner.lifecycleScope.launch {

        mapViewModel.regionSearch.flowWithLifecycle(viewLifecycleOwner.lifecycle, STARTED).collectLatest {
            Log.d("it_data", it.toString()) // SearchResponse 전체가져옴

            it?.documents?.firstOrNull()?.let { document ->
                Log.d("documents__",document.toString()) // SearchDocumentsResponse의 첫번째값 가져옴
                setMapData(document)
            }
        }
    }
}

단일흐름을 사용한 flowWithLifecycle() 로 수정한 코드

 

 

 

 

 

 

# 참고자료

https://medium.com/@namnpse/launching-coroutines-collecting-flow-with-lifecycle-scope-in-a-correct-way-973a7e1bfe63

 

Launching Coroutines, Collecting Flow with Lifecycle scope in a correct way

Coroutines have become very popular among Android developers in recent years, as they offer a simpler and more concise way to write…

medium.com

https://medium.com/jaesung-dev/launchwhenx-api-deprecated-%EC%84%9C%EC%82%AC-16c81e1a1073

 

launchWhenX API Deprecated 서사

(Release Note) androidx.lifecycle 2.6.0-alpha04

medium.com