[Android/Async]Coroutine

2023. 2. 24. 09:47Android/도구 및 라이브러리

728x90
반응형

Coroutine이란?

참고

  • Co(협력)+Routine(하나의 태스크, 함수)
  • Routine에는 두가지가 존재: Main Routine, Sub Routine
    • Sub Routine은 Main에서 호출하는 시점에서 진입, return을 만나면 탈출
    • Coroutine은 함수에 진입할 수 있는 진입점도 여러개, 빠져나가는 탈출점도 여러개
      • return 문이나 마지막 닫는 괄호를 만나지 않더라도 언제든 나가고 들어갈 수 있음
// 스레드의 main 함수가 drawPerson()을 호출하면 하나의 코루틴 블럭(함수)이 생성됨
// drawPerson()은 언제든 진입, 탈출할 수 있는 자격이 주어짐
fun drawPerson() {
    /* 실제로 startCoroutine은 없음. 직관적 이해를 위해 이 코드에서만 사용 */
    startCoroutine {
        // 코루틴 함수가 실행되는 과정에서 suspend 키워드를 가진 함수를 만나게 되면,    
        // 더이상 아래 코드를 실행하지 않고 멈춤(suspend) 후 코루틴 블럭 탈출
        drawHead()
        drawBody()
        drawLegs()
        // 다른 코드들이 실행되다가도, drawHead가 끝이나면
        // 다시 코루틴으로 진입해 아까 멈춘 부분(drawHead) 아래부터 다시 실행됨
    }
}

suspend fun drawHead() {
    delay(2000)
}

suspend fun drawBody() {
    delay(5000)
}

suspend fun drawLegs() {
    delay(3000)
}

LifecycleScope란?

Kotlin 코루틴은 비동기 코드를 작성할 수 있게 하는 API를 제공함.

Kotlin 코루틴을 사용하면 코루틴이 실행되어야 하는 시기를 관리하는 데 도움이 되는 CoroutineScope를 정의할 수 있음

LifecycleScope는 각 Lifecycle 객체에서 정의됨.

이 범위에서 실행된 코루틴은 Lifecycle이 끝날 때 제거됨.

lifecycle.coroutineScope 또는 lifecycleOwner.lifecycleScope 속성을 통해 Lifecycle의 CoroutineScope에 엑섹스 가능

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val params = TextViewCompat.getTextMetricsParams(textView)
            val precomputedText = withContext(Dispatchers.Default) {
                PrecomputedTextCompat.create(longTextContent, params)
            }
            TextViewCompat.setPrecomputedText(textView, precomputedText)
        }
    }
}

재시작 가능한 수명 주기 인식 코루틴

Lifecycle과 LifecycleOwner는 실행 정지 repeatOnLifecycle API 제공

class MyFragment : Fragment() {

    val viewModel: MyViewModel by viewModel()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // lifecycle coroutine 생성
        viewLifecycleOwner.lifecycleScope.launch {
            // repeatOnLifecycle launches the block in a new coroutine every time the
            // lifecycle is in the STARTED state (or above) and cancels it when it's STOPPED.
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                // Trigger the flow and start listening for values.
                // This happens when lifecycle is STARTED and stops
                // collecting when the lifecycle is STOPPED
                viewModel.someDataFlow.collect {
                    // Process item
                }
            }
        }
    }
}

수명주기 인식 코루틴 정지

Lifecycle은 lifecycle.whenCreated, lifecycle.whenStarted, lifecycle.whenResumed와 같은 추가 메서드 제공

-> 블록 내부에서 실행되는 코루틴은 Lifecycle이 원하는 최소한의 상태가 아니면 정지됨

class MyFragment: Fragment {
    init { // Notice that we can safely launch in the constructor of the Fragment.
        lifecycleScope.launch {
            whenStarted {
                // The block inside will run only when Lifecycle is at least STARTED.
                // It will start executing when fragment is started and
                // can call other suspend methods.
                loadingView.visibility = View.VISIBLE
                val canAccess = withContext(Dispatchers.IO) {
                    checkUserAccess()
                }

                // When checkUserAccess returns, the next line is automatically
                // suspended if the Lifecycle is not *at least* STARTED.
                // We could safely run fragment transactions because we know the
                // code won't run unless the lifecycle is at least STARTED.
                loadingView.visibility = View.GONE
                if (canAccess == false) {
                    findNavController().popBackStack()
                } else {
                    showContent()
                }
            }

            // This line runs only after the whenStarted block above has completed.

        }
    }
}

코루틴이 활성 상태인 동안 when 메서드 중 하나를 통해 Lifecycle이 끝나면 코루틴은 자동 취소됨

class MyFragment: Fragment {
    init {
        lifecycleScope.launchWhenStarted {
            try {
                // Call some suspend functions.
            } finally {
                // This line might execute after Lifecycle is DESTROYED.
                if (lifecycle.state >= STARTED) {
                    // Here, since we've checked, it is safe to run any
                    // Fragment transactions.
                }
            }
        }
    }
}
728x90
반응형

'Android > 도구 및 라이브러리' 카테고리의 다른 글

[Android]DeepLink와 Scheme  (0) 2023.05.29
[Android/Async]RxJava에서 Throttle과 Debounce  (0) 2023.05.10
[Android]Deeplink  (0) 2023.02.25
[Android/Library]Eventbus  (0) 2023.02.24
[Android/Async]RxJava  (0) 2023.02.24