Android Acitivty 또는 Fragment는 자체 수명주기와 함께 제공된다.
앞서 말한 생명주기와 비동기 작업이 구조적 동시성(Structed concurrency)을 달성하기 위해선 GlobalScope와 함께 코루틴을 실행하는 것은 좋은 옵션이 아니다.
더 나은 접근 방식을 선정해야하는데 Android 구성 요소로 코루틴 범위를 제한하는 것이 하나의 방법이다.
Android 아키텍처 구성 요소를 사용하면 코루틴을 훨씬 더 쉽게 사용할 수 있다.
ViewModel에서의 코루틴
☞ Job 객체 생성
☞ Job 및 Dispatcher를 이용해 CoroutineScope를 생성
☞ CoroutineScope에서 코루틴 빌더(launch, async)를 사용한다.
☞ onCleared를 오버라이드하여 ViewModel이 종료되는 시점에 코루틴 작업이 취소될 수 있도록 Job 객체를 취소한다.
class UserViewModel : ViewModel() {
private val job = Job()
private val uiScope = CoroutineScope(Dispatchers.Main + job)
fun doSomeOperation() {
uiScope.launch {
//Working on UI thread
print(Thread.currentThread().name)
//Use dispatcher to switch between context
val deferred = async(Dispatchers.Default) {
//Working on background thread
10 + 10
}
//Working on UI thread
print(deferred.await())
}
}
override fun onCleared() {
super.onCleared()
job.cancel()
}
}
Activity, Fragment에서의 코루틴
☞ CoroutineScope 인터페이스를 구현
☞ Job 객체를 초기화
☞ CoroutineContext를 상속받아 Job 객체와 사용할 스레드를 정의하여 Dispatcher를 지정
☞ onDestroy를 상속받아 라이플 사이클이 종료되는 시점 코루틴 작ㅇ버이 취소되도록 Job 객체를 취소
class MainActivity : AppCompatActivity(), CoroutineScope {
private lateinit var mJob: Job
override val coroutineContext: CoroutineContext
get() = mJob + Dispatchers.Main
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mJob = Job()
launch {
//Working on UI thread
print(Thread.currentThread().name)
//Use dispatcher to switch between context
val deferred = async(Dispatchers.Default) {
//Working on background thread
10 + 10
}
//Working on UI thread
print(deferred.await())
}
}
override fun onDestroy() {
super.onDestroy()
mJob.cancel()
}
}
이렇게 ViewModel, Activity, Fragment에서 코루틴을 사용하는 방법을 확인했다.
예외처리는 개발자가 직접 처리해야 하기에 CoroutineExceptionHandler 객체를 만들어 코루틴 빌더에 전달하면 된다. 코루틴 빌더 내에서 예외가 발생하면 핸들러를 이용하여 처리할 수 있지만, 코루틴익셉션핸들러 객체는 개발자가 처리하지 않을 것으로 판단하는 예외를 호출하기 때문에 async에 등록하는 것은 효과가 없다.
private val handler = CoroutineExceptionHandler { coroutineContext, throwable ->
Log.e("Exception :", "예외 상황 - " + throwable)
}
uiScope.launch(handler) {
//Working on UI thread
print(Thread.currentThread().name)
//Use dispatcher to switch between context
val deferred = async(Dispatchers.Default) {
//백그라운드 스레드 에서 동작하며 예외를 발생!!
throw IOException()
}
//UI 스레드 에서 동작 하며, await를 호출 전까지는 예외를 발생시키지 않는다.
deferred.await()
}
'Coroutine' 카테고리의 다른 글
Coroutines - Part. 6 CoroutineContext 및 Dispatchers (0) | 2021.01.30 |
---|---|
Coroutines - Part. 5 안드로이드에서의 코루틴 - 동기식과 비동기식, 콜백과 코루틴 (0) | 2021.01.30 |
Coroutines - Part. 3 withTimeout(), withTimeoutOrNull() (0) | 2021.01.30 |
Coroutines - Part. 2 취소, 취소할 수 없는 블럭 (0) | 2021.01.30 |
Coroutines - Part 1. 완료 대기, 지연 실행 (0) | 2021.01.30 |