Android 에서 비동기 실행을 할때 본인은 간혹 실수하여 에러를 마주하곤 한다.
바로 View 를 UI Thread 에서 변경하지 않아서 발생하는 것이 그것이다.
안드로이드 시스템은 애플리케이션이 실행되면 하나의 실행 스레드로 애플리케이션의 프로세스를 실행하는데, 이것을 메인 스레드라고 한다.
UI 도구 키트 구성 요소를 생성 및 조작할 때 상호작용하는 스레드가 MainThread 이며, 그렇기 때문에 UI Thread 라고도 불린다.
Main Thread 에서는 오래 소요되는 작업을 수행하지 않는 것을 권장하는데, 오래 소요되어 응답성/반응성이 떨어진다면 사용성이 떨어지거나 ANR 이 발생할 수 있기 때문이다.
따라서, 안드로이드 스레드 사용 시 아래와 같은 사항을 유념해야한다.
- 시간이 오래걸리는 작업은 UI 스레드로부터 분리하고, 별도의 스레드에서 실행하여 UI 스레드 작업이 지연/차단되는 것을 방지해야한다.
- UI 스레드가 아닌 스레드에서 UI component 를 조작할 수 없다.
그렇다면 불가피하게 메인 스레드가 아닌 스레드의 결과에 따라 UI 를 변경해주어야하는 경우에는 어찌 처리되어야하는가?
Activity.runOnUiThread(Runnable r)
Developers 가이드에는 해당 메서드에 대해 이렇게 설명하고 있다.
“특정 동작을 UI 스레드에서 동작하도록 한다. 만약 현재 스레드가 UI 스레드이면 그 동작은 즉시 수행되고, 그렇지 않으면 필요한 동작을 UI 스레드의 이벤트 큐로 전달한다.”
해당 메서드의 구현부를 살펴보면, Handler 를 이용해 runnable 을 전달한다. (UI Thread에 Queue 의 형태로 enqueue 된다.)
startActivity 를 통해서 생성되는 ActivityThread 는 UI thread Looper와 Handler를 생성하는데 loop 을 돌면서 전달된 runnable 을 처리한다.
문제점! 만일 종료가 되면…?
여기서 한번 더 나아가보자.
runOnUiThread 를 다운로드 혹은 Request 의 결과가 success이면 수행하는 로직이 있다고 가정했을 때, 만일 어떠한 연유로 크래시가 나면 전달된 runnable 은 어찌될까?
thread 객체를 만들고 start 하면 다른 스레드가 실행되므로, onDestroy 를 해도 다른 스레드는 중지되지 않고 main thread 에서 이를 강제 중지할 수는 없다. 따라서, onDestroy 에서 프로그램을 안전하게 종료할 수 있도록 해야하는 등 스레드 관리에 별도의 작업이 필요하다.
그 외
이렇게 스레드를 관리하는 것은 보일러 플레이트 코드(반복적으로 비슷한 형태를 띄는 코드)들을 유발하고 복잡하게 한다.
따라서, RxJava 나 Corouine 등을 사용하여 편리하게 구현하는 것을 권장한다.
+) 본래, AsyncTask 를 이용한 방법이 제공되었으나, 이는 deprecated 되었다.
참고 링크
Uploaded by
N2T