장기 실행 작업을위한 Android AsyncTask


91

여기 에있는 AsyncTask에 대한 문서를 인용하면 다음과 같습니다.

AsyncTasks는 짧은 작업 (최대 몇 초)에 이상적으로 사용되어야합니다. 스레드를 장기간 실행해야하는 경우 다음과 같이 java.util.concurrent pacakge에서 제공하는 다양한 API를 사용하는 것이 좋습니다. Executor, ThreadPoolExecutor 및 FutureTask.

이제 내 질문이 생깁니다. 왜? 이 doInBackground()함수는 UI 스레드에서 실행되므로 여기서 장기 실행 작업을 수행하면 어떤 해가 있습니까?


2
asyncTask를 사용하는 앱을 실제 장치에 배포 할 때 직면 한 문제 doInBackground는 진행률 표시 줄을 사용하지 않으면 장기 실행 기능이 화면을 고정한다는 것입니다.
venkatKA

2
AsyncTask는 시작된 Activity에 연결되어 있기 때문에 Activity가 종료되면 AsyncTask 인스턴스도 종료 될 수 있습니다.
IgorGanapolsky

서비스 내에서 AsyncTask를 생성하면 어떻게됩니까? 문제가 해결되지 않습니까?
eddy

1
IntentService, Perfect solution을 사용하여 백그라운드에서 장시간 작업을 실행하십시오.
Keyur Thumar

답변:


120

매우 좋은 질문입니다. Android 프로그래머로서 문제를 완전히 이해하려면 시간이 걸립니다. 실제로 AsyncTask에는 관련된 두 가지 주요 문제가 있습니다.

  • 활동 수명주기와 잘 연결되어 있지 않습니다.
  • 그들은 매우 쉽게 메모리 누수를 만듭니다.

내부 RoboSpice (동기 부여 응용 프로그램 Google Play에서 사용할 수 ) 우리는 세부에서 그 질문에 대답. AsyncTasks, 로더, 기능 및 단점에 대한 심층적 인보기를 제공하고 네트워크 요청에 대한 대체 솔루션 인 RoboSpice를 소개합니다. 네트워크 요청은 Android의 일반적인 요구 사항이며 본질적으로 장기 실행 작업입니다. 다음은 앱에서 발췌 한 것입니다.

AsyncTask 및 활동 수명주기

AsyncTask는 활동 인스턴스의 수명주기를 따르지 않습니다. 활동 내에서 AsyncTask를 시작하고 장치를 회전하면 활동이 파괴되고 새 인스턴스가 생성됩니다. 그러나 AsyncTask는 죽지 않을 것입니다. 완료 될 때까지 계속 살아갑니다.

완료되면 AsyncTask는 새 활동의 UI를 업데이트하지 않습니다. 실제로 더 이상 표시되지 않는 활동의 이전 인스턴스를 업데이트합니다. 이로 인해 java.lang.IllegalArgumentException 유형의 예외가 발생할 수 있습니다. 예를 들어, 활동 내에서보기를 검색하기 위해 findViewById를 사용하는 경우 창 관리자에보기가 첨부되지 않습니다.

메모리 누수 문제

AsyncTask를 활동의 내부 클래스로 만드는 것은 매우 편리합니다. AsyncTask는 작업이 완료되거나 진행 중일 때 Activity의 뷰를 조작해야하므로 Activity의 내부 클래스를 사용하는 것이 편리해 보입니다. 내부 클래스는 외부 클래스의 모든 필드에 직접 액세스 할 수 있습니다.

그럼에도 불구하고 내부 클래스는 외부 클래스 인스턴스 인 Activity에 대해 보이지 않는 참조를 보유 할 것임을 의미합니다.

장기적으로 이로 인해 메모리 누수가 발생합니다. AsyncTask가 오래 지속되면 활동이 "살아있는"상태를 유지하는 반면 Android는 더 이상 표시 할 수 없기 때문에이를 제거하려고합니다. 활동은 가비지 수집 될 수 없으며 Android가 기기의 리소스를 보존하는 중심 메커니즘입니다.


장기 실행 작업에 AsyncTasks를 사용하는 것은 정말 매우 나쁜 생각입니다. 그럼에도 불구하고 1 ~ 2 초 후에 View를 업데이트하는 것과 같이 수명이 짧은 경우에는 괜찮습니다.

RoboSpice Motivations 앱 을 다운로드하는 것이 좋습니다.이 은이를 심층적으로 설명하고 일부 백그라운드 작업을 수행하는 다양한 방법에 대한 샘플 및 데모를 제공합니다.


@Snicolas 안녕하세요. NFC 태그에서 데이터를 스캔하여 서버로 보내는 앱이 있습니다. 좋은 신호 영역에서 잘 작동하지만 웹 호출을 계속 실행하는 AsyncTask 신호가없는 경우. 예를 들어 진행률 대화 상자가 몇 분 동안 실행 된 다음 사라지면 화면이 검게 변하고 응답하지 않습니다. 내 AsyncTask는 내부 클래스입니다. X 초 후에 작업을 취소하는 핸들러를 작성 중입니다. 앱은 스캔 후 몇 시간 동안 오래된 데이터를 서버로 보내는 것 같습니다. AsyncTask가 완료되지 않고 몇 시간 후에 완료 되었기 때문일 수 있습니까? 나는 어떤 통찰력을 주시면 감사하겠습니다. 감사합니다
turtleboy jul.

무슨 일이 일어나는지 추적하십시오. 하지만 네, 가능합니다! 당신이 당신의 AsyncTask를을 desin 경우에, 당신은 ... 당신은 RS 또는 서비스로 마이그레이션하지 않으려면 그 지점을 시작하는 좋은 것, 오히려 제대로을 취소 할 수 있습니다
Snicolas

@Snicolas 답장을 보내 주셔서 감사합니다. 나는 어제 내 문제를 설명하고 8 초 후에 AsyncTask를 중지하기 위해 작성한 핸들러 코드를 보여주는 게시물을 작성했습니다. 시간이 있으면 한번 봐도 될까요? 핸들러에서 AsyncTask.cancel (true)를 호출하면 작업이 제대로 취소됩니까? 내 doInBackgroud에서 iscancelled ()의 값을 주기적으로 확인해야한다는 것을 알고 있지만 한 줄의 웹 호출 HttpPost를 만들고 UI에 업데이트를 게시하지 않기 때문에 내 상황에 적용되지 않는다고 생각합니다. 예는 IntentService에서 HttPost을 할 수 있습니다
turtleboy


RoboSpice (github에서)를 시도해야합니다. )
Snicolas

38

왜 ?

때문에 AsyncTask, 기본적으로 스레드 풀 사용 하면 만들지 않은가 . 풀의 요구 사항이 무엇인지 모르기 때문에 생성하지 않은 풀의 리소스를 묶지 마십시오. 그리고 여기에있는 경우처럼 해당 풀에 대한 문서에서하지 말라고 지시하는 경우 생성하지 않은 풀의 리소스를 묶지 마십시오.

특히, 안드로이드 3.2에서 사용하는 스레드 풀로 시작하는 AsyncTask(와 애플 리케이션을 위해 기본적으로 android:targetSdkVersion단지가 13 이상으로 설정) 무기한이 스레드를 묶어 경우, 다른 작업을 하나도 실행되지 않습니다 - 그것은 스레드를.


이 설명에 감사드립니다 .. 장기 실행 작업에 AsyncTasks를 사용하는 것에 대해 진정으로 잘못된 것을 찾을 수 없었지만 (일반적으로 서비스에 위임하지만) 해당 ThreadPool을 묶는 것에 대한 귀하의 주장 (실제로 할 수있는 크기에 대한 가정을하지 마십시오.) 서비스 사용에 대한 Anup의 게시물에 대한 보충 자료 : 해당 서비스는 자체적으로 메인 스레드를 차단하지 않고 백그라운드 스레드에서 작업을 실행해야합니다. 옵션은 IntentService이거나 더 복잡한 동시성 요구 사항의 경우 고유 한 멀티 스레딩 전략을 적용 할 수 있습니다.
baske

서비스 내에서 AsyncTask를 시작해도 동일합니까 ?? 장기 실행 작업이 여전히 문제가 될까요?
eddy

1
@eddy : 예, 스레드 풀의 특성은 변경되지 않습니다. A에 대한 Service그냥 사용 Thread또는를 ThreadPoolExecutor.
CommonsWare

@CommonsWare에게 마지막 질문에 감사드립니다. TimerTasks는 AsyncTasks와 동일한 단점을 공유합니까? 아니면 완전히 다른가요?
eddy

1
@eddy : TimerTaskAndroid가 아닌 표준 Java에서 가져온 것입니다. (이름에도 불구하고 표준 Java의 일부 임) TimerTask에 찬성하여 대부분 포기되었습니다 ScheduledExecutorService. 둘 다 Android에 연결되어 있지 않으므로 백그라운드에서 실행될 것으로 예상되는 경우 여전히 서비스가 필요합니다. 그리고 Android 에서을 ( 를) 고려해야 AlarmManager하므로 시계 틱을 보는 것만으로도 서비스가 필요하지 않습니다.
CommonsWare

4

Aysnc 작업은 여전히 ​​앱 GUI와 함께 사용되지만 UI 스레드의 리소스가 많은 작업을 유지하는 특수 스레드입니다. 따라서 목록 업데이트, 뷰 변경 등과 같은 작업에서 가져 오기 작업 또는 업데이트 작업을 수행해야하는 경우 이러한 작업을 UI 스레드에서 제외 할 수 있도록 비동기 작업을 사용해야하지만 이러한 작업은 여전히 ​​UI에 연결되어 있습니다. .

UI 업데이트가 필요하지 않은 장기 실행 작업의 경우 UI 없이도 살 수 있기 때문에 서비스를 대신 사용할 수 있습니다.

따라서 짧은 작업의 경우 생성 활동이 종료 된 후 OS에 의해 종료 될 수 있으므로 비동기 작업을 사용하십시오 (보통 작업 중에는 종료되지 않지만 작업을 완료합니다). 길고 반복적 인 작업에는 대신 서비스를 사용하십시오.

자세한 내용은 스레드 참조 :

몇 초 이상 AsyncTask?

AsyncTask는 활동이 파괴 된 경우에도 중지되지 않습니다.


1

AsyncTask의 문제점은 활동의 비 정적 내부 클래스로 정의 된 경우 활동에 대한 참조가 있다는 것입니다. 비동기 작업의 컨테이너가 작업을 완료하지만 AsyncTask의 백그라운드 작업이 계속되는 시나리오에서 작업 개체는 참조가 있기 때문에 가비지 수집되지 않으므로 메모리 누수가 발생합니다.

이를 해결하는 해결책은 비동기 작업 을 활동의 정적 내부 클래스로 정의 하고 컨텍스트에 대한 약한 참조를 사용하는 것입니다.

그러나 여전히 간단하고 빠른 백그라운드 작업에 사용하는 것이 좋습니다. 깨끗한 코드로 앱을 개발하려면 RxJava 를 사용 하여 복잡한 백그라운드 작업을 실행하고 그 결과로 UI를 업데이트하는 것이 좋습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.