본문으로 바로가기


안녕하세요 PEACE-에요.

안드로이드 스터디 [열 번째]글이네요.


오늘은 비동기 처리를 위한 AsyncTask에 대해 포스팅하겠습니다.




1. 메인쓰레드(UI Thread)와 비동기 처리


우리가 사용하는 안드로이드 어플리케이션에서 UI(버튼, 리스트, 텍스트뷰 등등..)는 UI쓰레드라고 불리는 메인쓰레드가 관여하고 처리한다. 그렇다면 우리가 만든 버튼을 통해 어떠한 작업을 수행한다면 메인쓰레드는 어떻게 처리할까? 우선 하나의 상황을 통해 설명하려한다. '777APP'이라는 어플리케이션에 '다운로드'와 '페이지 닫기'라는 두 개의 버튼이 구성되어있다. 그리고 다운로드 버튼을 클릭해 해당 파일을 다운로드 하려한다. 이때 메인쓰레드가 수행하도록 코드를 구성했다면 버튼에 대한 처리는 메인쓰레드가 할 것이며, 다운로드하는 처리도 메인쓰레드가 할 것이다. 또한 다운로드 받는 동안 타 UI와의 교류가 비활성화 될 것이다. 쉽게말해 '다운로드' 버튼과 '페이지 닫기' 버튼이 먹통이 될 것이다. 그렇다면 어떻게 해야할까? 기다려야할까? 아니다. 사용자는 그것을 원치 않을 것이다. 이때 우리는 메인쓰레드와 별개로 작업을 수행하고 그 결과를 UI에 나타낼 수 있도록 처리해야한다. '비동기 처리'라고 하며, 이를 위해 AsyncTask에 대해 알아 볼 것이다.




2. AsyncTask란?


AsyncTask메인쓰레드에서 수행될 작업을 수행해주는 비동기적 처리 방법 중 하나라고 했다. 아래 사진은 AsyncTask에 대한 이해를 돕기 위해 안드로이드 디벨로퍼스의 AsyncTask Guide를 발췌해온 글이다.

위 내용은 구글 번역기에 이용해 확인할 수 있다. 그래서 나는 중요 포인트만 짚고 넘어가려한다. 우선 AsyncTask 메인쓰레드를 작업을 좀 더 효율적이게 해줄 수 있는 백그라운드 처리 기법이다.  AsyncTask는 작업 수행 시간이 수 초간 진행될 때 유용하며, 오랜 시간 작업을 해야하는 경우에는 AsyncTask가 아닌 다른 방법을 권장한다. 예를들면 java.util.concurrent패키지에서 제공하는 Executor, ThreadPoolExecutor 및 FutureTask가 있다.




3. AsyncTask에는 무엇이 있을까?



[그림 1] AsyncTask의 Override 메서드


[그림 1]은 AsyncTask에서 지원하는 메서드들과 그에 대한 쓰임을 나타낸 것이다. 이제 쉽게 다룰 수 있을 것이며, 사용법과 주의점만 파악한다면 좀 더 퀄리티있는 소스 코딩이 가능할 것이다.




4. AsyncTask 사용 방법



[그림 2] AsyncTask 사용 방법


[그림 2]에서 보면 execute()를 통해 작업을 수행하며 인자의 자료형은 doInBackground()의 매개변수의 자료형과 같다. 또한 이 자료형의 변수는 가변인자이며 단일 변수나 배열과 같은 형태의 변수를 사용할 수 있다. doInBackground()에서 가변 형태인 매개변수 사용 시에는 변수명[0]과 같이 배열의 형태로 사용한다.


AsyncTask 작업을 수행하기 위해서는 객체를 생성해 execute()메서드와 executeOnExecutor()메서드를 호출하는 방법이 있다.

  **execute() 메서드 호출을 통한 작업 수행

      : 일반적인 사용하는 수행 방법이며 여러 AsyncTask 객체를 만들어 다수의 작업을 수행할 때 execute()가 호출된 순서대로 처리.

  **executeOnExecutor() 메서드 호출을 통한 작업 수행
      : 병렬처리를 위한 수행 방법이며 여러 AsyncTask 객체를 만들어 다수의 작업을 수행할 때 executeOnExecutor()가 호출된 순서에

        상관 없이 동시처리한다.




5. AsyncTask 주의점


AsyncTask 수행을 위해 생성된 객체는 execute()를 통해 단 한번만 실행 가능(1)하며, 재 실행시 예외 상황이 발생한다. 또한 AsyncTask메인쓰레드에서만 실행되고 호출되어야한다(2). AsyncTask는 백그라운드에서 수행되며, 그 결과를 메인쓰레드에 전달해 사용자에게 제공한다. 그렇다면 AsyncTask에 백그라운드 작업을 요청한 메인쓰레드, 즉 AsyncTask를 호출한 Activitydestroy된다면 어떻게될까? 여기서부터 문제가 발생한다. 일반적으로 특별한 처리를 해두지 않았다면 AsyncTask는가 참조하고있던 UI가 사라져도 AsyncTask는 백그라운드에서 작업을 수행한다. 그리고 개발자의 코드에 의해 그 결과를 사라진 메인쓰레드에 넘겨주려 할 것이며, 이 과정에서 사라진 UI를 참조하게된다. 하지만 자신이 참조하는 UI는 이미 destroy되었으며 예외 상황이 발생하게된다. 또한 가비지컬렉터는 AsyncTask가 참조하고 있는 이전 Activity를 컬렉트할 수 없어 메모리릭이 발생할 수 있다. 또한 화면 회전에 의해 Activitydestroy되고 새 인스턴스로 Activity를 생성할때도 이와같은 상황이 발생할 수 있다. 이를 위한 대비를 해야하며, cancel()을 통해 doInBackground() 실행 완료 후, onPostExcute() 호출을 막고 onCancelled를 호출하도록 해야한다(3). 마지막으로 AsyncTask를 여러 개 실행하면 이는 순차적으로 수행이 이뤄진다. ATask.execute()와 BTask.execute()를 순서대로 호출하면 ATask에 대한 작업이 끝나야 BTask에 대한 작업이 수행된다는 뜻이다. 그렇다면 동시에 처리하려면 어떻게해야할까? 이를 위해 execute() 메서드 대신 executeOnExecutor()라는 메서드가 제공되며 이를 사용해 병렬처리가 가능하다.











 댓글공감은 환영입니다.