안드로이드 코루틴

sumi Yoo·2022년 10월 15일
0

코루틴

스레드 안에서 실행되는 일시 중단 가능한 작업의 단위로, 경량 스레드

코루틴과 스레드의 차이점

코루틴은 컨텍스트 스위치가 발생하지 않아 스레드보다 비용이 덜 든다.

CoroutineScope

코루틴의 범위로 코루틴의 블록을 묶음으로 제어할 수 있는 단위

GlobalScope

CoroutineScope의 한 종류로 Application 생명주기에 종속적.
Activity가 onDestroy되어도 동작하는 코루틴 Context

Dispatcher

CoroutineContext의 주요 요소로 CoroutineContext를 상속받아 어떤 스레드에서 어떻게 동작할 것인가에 대한 정의

  • Dispatchers.Main: 메인 스레드에서 동작하는 방식
  • Dispatchers.IO: 네트워크/파일 작업에 사용하는 방식
  • Dispatchers.Default: CPU 사용량이 많은 작업에 사용

=> Main을 제외한 IO/Default는 백그라운드 작업

launch() & async()

scope의 확장함수로서, 코루틴을 만들고 실행하는 코루틴 빌더
launch: job 반환, 반환값이 없음
async: Deffered<T> 반환(T는 반환값의 자료형), 반환값 존재

withContext() - T 반환

async처럼 결과값을 반환하는 빌더로 async와 유사하지만, withContext()는 Deferred<T>객체로 반환하지 않고, 결과(T)를 그 자리에서 반납한다

코루틴 제어

job 객체

대기 - join(), joinAll()
중단 - cancle(): 부모(job)을 포함해 모두 종료하는 함수로 한번 cancle하면 재사용이 불가은
cancleChildern(): 부모를 제외한 하위 루틴들을 모두 종료

Deffered<T> 객체

대기 - await() 로 대기하고 결과값을 전해 받음, awaitAll()

코루틴 지연실행

코루틴 빌더(launch/async)의 start 인자에 CoroutineStart.Lazy값을 할당하면 해당 코루틴을 호출하는 시점에 실행

runBlocking - T 반환

코드 블럭이 작업이 완료될 때 까지 스레드를 점유하고 대기

예외처리 Exception

// 예외 처리를 할 수 없어, 앱이 죽어버리는 방법
GlobalScope.launch(Dispatchers.IO) {	// IO, 백그라운드 환경
    launch {
        throw Exception()	// 임의로 Exception 발생
    }
}

ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ

// 코루틴 선언 시 handler를 추가하여 예외 발생 시 콜백으로 처리하는 방법
GlobalScope.launch(Dispatchers.IO + handler) {    // 1
    launch {
        throw Exception()   // 2
    }
}

val handler = CoroutineExceptionHandler { coroutineScope, exception ->   // 3
    Log.d(TAG, "$exception handled!")
}

// 예외 발생 시 handler에 콜백으로 처리하여 앱이 죽지 않는 방법

CoroutineExceptionHandler: 예외 발생 시 등록한 handler에 위임하여 콜백으로 예외 이벤트를 처리하는 방식

but, async() / withContext()는 핸들러를 등록하여 throw로 예외처리 방법이 불가능

GlobalScope.launch(Dispatchers.IO) {
    try {
    	// withContext의 외부에 try~catch로 예외 처리 가능한 방법
        val name = withContext(Dispatchers.Main) {	
            throw Exception()
        }
    } catch (e: java.lang.Exception) {
        Log.d(TAG, "$e handled!")
    }
}

-> withContext 코루틴 블럭의 외부에 try-catch를 선언하여 예외 발생 시 처리할 수 있는 방법, async도 동일

delay()

스레드의 sleep() 메서드는 스레드를 점유하고 대기하는 Blocking 함수
코루틴의 delay() 메서드는 스레드를 점유하지 않는 non-blocking 함수

CoroutineContext

코루틴을 어떻게 처리할 것인지에 대한 여러가지 정보들의 모음.

취소 (Cancellation)

코루틴은 내부적으로 취소 동작을 위해 CancellationException을 사용
CancellationException 예외는 모든 핸들러들이 무시하므로 handler를 등록해도 아무런 효과가 없습니다.
코루틴 동작 중 취소 상황 시 처리를 해야할 일이 있다면 try-catch블록을 이용해서 예외처리용으로 사용이 가능

fun main(args: Array<String>) = runBlocking<Unit> {
    val job = launch {
		// child 코루틴 생성
        val child = launch {
            try {
                delay(Long.MAX_VALUE)	// Long자료형 최대값만큼 대기
            } catch (e :CancellationException) {	// CancellationException 예외 발생 처리
                println("Child is cancelled")
            }
        }
        yield()		// Thread순서 양보, 생략 시 child코루틴이 시작도 전에 cancel실행 가능
        println("Cancelling child")
        child.cancelAndJoin()	// child 코루틴 취소/대기
        yield()
        println("Parent is not cancelled")
    }
    job.join()
}

예외 (Exception)

일반적인 코루틴은 취소예외 이외의 예외는 양방향 전파라는 점

  • 양방향 전파 : 아래 방향(부모 -> 자식) + 위 방향 (자식 -> 부모) 모두 전파
    부모 예외로 인한 취소 발생 시 모든 자식 종료
    자식 예외로 인한 취소 발생 시 부모 / 모든 자식 종료

SupervisorJob (감독자 작업)

SupervisorJob은 일반적인 Job과 다르게 예외를 단방향전파
(예외로 인한 코루틴의 취소가 단방향/아래 방향 (부모 -> 자식)으로만 전파된다는 점)

  • 단방향 전파 : 아래 방향(부모 -> 자식)만 전파되는 것
    부모 예외로 인한 취소 발생 시 모든 자식 종료
    자식 예외로 인한 취소 발생 시 해당 Job만 종료

supervisorScope

블록 내부의 모든 코루틴에 SupervisorJob을 설정하고 싶을 때 사용.

0개의 댓글

관련 채용 정보