ANR (Activity Not Response)
액티비티가 응답하지 않는 오류 상황
액티비티를 작성할 때 ANR을 고려하지 않으면 앱이 수시로 종료될 수 있다
액티비티로 구성한 앱화면은 사용자 이벤트에 빠르게 반응해야 한다.
그런데 액티비티가 사용자 이벤트에 5초 이내에 반응하지 않으면 ANR 오류가 발생한다.
시스템에서 액티비티를 수행하는 수행 흐름을 메인 스레드 또는 UI 스레드라고 한다.
메인 스레드가 오래 걸리는 작업을 실행한다고 해서 그 자체로 오류가 발생하지는 않는다.
아무리 오래 걸려도 사용자가 액티비티 화면을 터치하지 않는 등 이벤트가 없다면 오류가 발생하지 않는다.
그러나 사용자가 언제 화면을 터치할 지 모르므로
액티비티를 작성할 때는 항상 ANR 오류를 고려해야 한다.
액티비티에서 시간이 오래 걸리는 대표적인 작업은 서버와 통신하는 네트워크이다.
물론 앱은 대부분 네트워크 통신을 지원하는 전문 라이브러리(Volley 또는 Retrofit2)를 사용해 만들며,
이 라이브러리는 내부적으로 ANR 문제를 고려해 작성되므로
해당 라이브러리를 사용할 때는 개발자가 ANR 문제를 고려하지 않아도 된다.
ANR 문제를 해결하는 방법은 액티비티를 실행한 메인 스레드 이외에 실행 흐름(개발자 스레드)을
따로 만들어서 시간이 오래 걸리는 작업을 담당하게 하면 된다.
그러나, 이 방법의 경우 ANR 오류는 해결되지만 화면을 변경할 수 없다는 또 다른 문제가 생긴다.
코루틴으로 ANR 오류 해결
코루틴
비동기 경량 스레드 (non-blocking lightweight thread)
안드로이드 시스템이 아니라 프로그래밍 언어에서 제공하는 기능
코틀린에서도 1.1 버전부터 코루틴을 지원하기 시작했으며 1.3 버전부터는 공식으로 지원한다.
코루틴은 수행 흐름을 여러 갈래로 만들어 여러 작업을 함께 처리한다.
결국 비동기 처리 방식과 같다.
일반적으로 비동기 처리라면 스레드를 생각하기 쉬운데
스레드는 성능에 문제가 많고 자유롭게 제어할 수 없거나 구현하기도 복잡하다.
따라서, 요즘은 스레드를 이용하지 않고 RX 프로그래밍이나 코루틴으로 비동기 처리를 구현한다.
코루틴은 스레드보다 가벼우면서 더 많은 기능을 제공한다.
안드로이드에서 코루틴 이용
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
안드로이드 앱에서 코루틴을 사용하려면 빌드 그래들 파일의 dependencies 항목에 등록해야 한다.
시간이 오래 걸리는 작업을 가정하여 코루틴을 알아보자.
var sum = 0L
var time = measureTimeMillis {
for (i in 1..2_000_000_000) {
sum += i
}
}
Log.d("time : $time")
binding.resultView.text = "sum : $sum"
=> 해당 코드는 ANR 오류가 발생한다.
같은 코드를 코루틴으로 작성
val channel = Channel<Int>()
# Dispatchers.Default : CPU를 많이 사용하는 작업을 백그라운드에서 실행
val backgroundScope = CoroutineScope(Dispatchers.Default + Job())
backgroundScope.launch {
var sum = 0L
var time = measureTimeMillis {
for (i in 1..2_000_000_000) {
sum += i
}
}
Log.d("time : $time")
channel.send(sum.toInt())
}
# Dispatchers.Main : 액티비티의 메인 스레드에서 동작하는 코루틴을 만듦 (화면에 결괏값 표시)
val mainScope = GlobalScope.launch(Dispatchers.Main) {
channel.consumeEach {
binding.resultView.text = "sum : $it"
}
}
코루틴을 구동하려면 먼저 스코프를 준비해야 한다.
해당 스코프에서 코루틴을 구동한다.
스코프는 성격이 같은 여러 코루틴이 동작하는 공간으로 이해할 수 있다.
한 스코프에 여러 코루틴을 구동할 수 있으며 한 애플리케이션에 여러 스코프를 만들 수 있다.
디스패처 : 스코프에서 구동한 코루틴이 어디에서 동작해야 하는지를 나타냄
- Dispatchers.Main : 액티비티의 메인 스레드에서 동작하는 코루틴을 만든다
- Dispatchers.IO : 파일에 읽거나 쓰기 또는 네트워크 작업 등에 최적화되었다
- Dispatchers.Default : CPU를 많이 사용하는 작업을 백그라운드에서 실행한다
Channel 클래스는 코루틴의 값을 전달받을 수 있는 방법을 제공한다.
Channel은 큐 알고리즘과 비슷하며 send() 함수로 데이터를 전달하면
그 데이터를 받는 코루틴에서는 receive()나 consumeEach() 등의 함수로 데이터를 받는다.
'Android' 카테고리의 다른 글
[Android] BottomNavigation + ViewPager2 (0) | 2022.04.06 |
---|---|
[Android] 코루틴 Coroutine (0) | 2022.04.01 |
[Android] 액티비티 컴포넌트 - 액티비티 생명주기 (0) | 2022.01.05 |
[Android] 액티비티 컴포넌트 - 인텐트 (0) | 2022.01.05 |
[Android] 안드로이드 앱의 기본 구조 (0) | 2022.01.04 |