본문 바로가기

Coroutine

Coroutines - Part. 4 안드로이드에서 코루틴 - ViewModel, Activity, Fragment

728x90

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()
        }

 

 

 

Coroutines for Android

Coroutines are a great way to handle asynchronous programming where it also offers an immense easy way to switch between context from…

proandroiddev.com