티스토리 뷰

Android/Coroutine

Android Coroutine - Cancel

강태종 2022. 1. 8. 01:10

cancen() & cancelAndJoin()

Coroutine에서 취소가 어떻게 진행되는지 확인해봅니다.

// cancel과 cancelAndJoin의 차이
public suspend fun Job.cancelAndJoin() {
    cancel()
    return join()
}

cancel()을 실행했을 때 취소되지 않고 Coroutine이 계속 실행됩니다. 즉 Coroutine 내부에서 진행될 때 취소를 확인하여 종료할 수 있도록 설계 해야합니다. (개발자가 직접 취소 지점을 정할 수 있습니다.)

 

val job = CoroutineScope(Dispatchers.IO).launch {
    for (i in 0 until 5) {
        Log.d("PASS", "Running")
        Thread.sleep(1000L)
    }
}

lifecycleScope.launch {
    delay(1000L)
    job.cancel()
}
2022-01-08 00:15:14.054 19334-19367/com.taetae98.coroutine D/PASS: Running
2022-01-08 00:15:15.055 19334-19367/com.taetae98.coroutine D/PASS: Running
2022-01-08 00:15:16.057 19334-19367/com.taetae98.coroutine D/PASS: Running
2022-01-08 00:15:17.060 19334-19367/com.taetae98.coroutine D/PASS: Running
2022-01-08 00:15:18.063 19334-19367/com.taetae98.coroutine D/PASS: Running

 

val job = CoroutineScope(Dispatchers.IO).launch {
    for (i in 0 until 5) {
        Log.d("PASS", "Running")
        Thread.sleep(1000L)
        yield()
    }
}

lifecycleScope.launch {
    delay(1000L)
    job.cancel()
}

 

val job = CoroutineScope(Dispatchers.IO).launch {
    for (i in 0 until 5) {
        if (isActive) {
            Log.d("PASS", "Running")
            Thread.sleep(1000L)
        }
    }
}

lifecycleScope.launch {
    delay(1000L)
    job.cancel()
}
2022-01-08 00:36:11.718 19690-19721/com.taetae98.coroutine D/PASS: Running
2022-01-08 00:36:12.721 19690-19721/com.taetae98.coroutine D/PASS: Running

위와 같이 2가지 방법으로 코딩했을 경우 정상적으로 종료된 것을 확인할 수 있다. 즉 개발자가 직접 yield(), isActive 등으로 비활성 상태에서 종료 지점을 정할 수 있습니다.


val job = CoroutineScope(Dispatchers.IO).launch {
    try {
        for (i in 0 until 5) {
            Log.d("PASS", "Running")
            yield()
            delay(1000L)
        }
    } catch (e: CancellationException) {
        Log.d("PASS", "ERROR : $e")
    }
}

lifecycleScope.launch {
    delay(1000L)
    job.cancel()
}
2022-01-08 00:44:19.600 20187-20221/com.taetae98.coroutine D/PASS: Running
2022-01-08 00:44:20.613 20187-20223/com.taetae98.coroutine D/PASS: ERROR : kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@43635db

실제로 Coroutine이 종료된 시점에서 yield(), delay() 등을 호출하면 CancellationException이 발생하는 것을 확인할 수 있습니다.


 

NonCancellable

이미 취소된 함수에서 어떠한 작업을 위해 suspend 함수를 호출해야 할 경우 보통의 상황에선 CancellationException이 발생할 것 입니다. withContext(NonCancellable)을 통해서 정지된 Coroutine에서 suspend 함수를 호출할 수 있습니다.

val job = CoroutineScope(Dispatchers.IO).launch {
    try {
        for (i in 0 until 5) {
            Log.d("PASS", "Running")
            yield()
            delay(1000L)
        }
    } catch (e: CancellationException) {
        Log.d("PASS", "ERROR : $e")
    } finally {
        withContext(NonCancellable) {
            delay(1000L)
            Log.d("PASS", "coroutine is finished!!")
        }
    }
}

lifecycleScope.launch {
    delay(1000L)
    job.cancel()
}
2022-01-08 00:58:58.531 20284-20319/com.taetae98.coroutine D/PASS: Running
2022-01-08 00:58:59.551 20284-20321/com.taetae98.coroutine D/PASS: ERROR : kotlinx.coroutines.JobCancellationException: StandaloneCoroutine was cancelled; job=StandaloneCoroutine{Cancelling}@43635db
2022-01-08 00:59:00.562 20284-20321/com.taetae98.coroutine D/PASS: coroutine is finished!!

 

withTimeout

withTimeout을 사용하여 지정된 시간에만 작동되는 Coroutine을 만들 수 있습니다. withTimeout을 통해 Exception이 발생한 경우 TimeoutCancellationException이 발생하고 CancellationException을 상속 받습니다.

 

public class TimeoutCancellationException internal constructor(
    message: String,
    @JvmField internal val coroutine: Job?
) : CancellationException(message), CopyableThrowable<TimeoutCancellationException> {
val job = CoroutineScope(Dispatchers.IO).launch {
    withTimeout(2000L) {
        try {
            for (i in 0 until 5) {
                Log.d("PASS", "Coroutine is running")
                delay(1000L)
            }
        } catch (e: TimeoutCancellationException) {
            Log.e("PASS", "Exception : $e")
        }
    }
}
2022-01-08 01:03:34.056 20418-20453/com.taetae98.coroutine D/PASS: Coroutine is running
2022-01-08 01:03:35.068 20418-20453/com.taetae98.coroutine D/PASS: Coroutine is running
2022-01-08 01:03:36.058 20418-20453/com.taetae98.coroutine E/PASS: Exception : kotlinx.coroutines.TimeoutCancellationException: Timed out waiting for 2000 ms

'Android > Coroutine' 카테고리의 다른 글

Android Coroutine - Exception  (0) 2022.01.16
Android Coroutine - Job Lifecycle  (0) 2022.01.15
Android Coroutine - Coroutine Builder  (0) 2022.01.07
Android Coroutine - CoroutineContext  (0) 2022.01.07
Android Coroutine - Scope  (0) 2022.01.07
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/07   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함