처리기 대 AsyncTask 대 스레드 [닫힘]


382

나는 약간의 차이점에 대해 혼동있어 Handlers, AsyncTaskThreads안드로이드한다. StackOverflow에서 꽤 많은 블로그와 질문을 읽었습니다.

HandlerUI와 통신 할 수있는 백그라운드 스레드입니다. 예를 들어 진행률 표시 줄 업데이트는을 통해 수행해야합니다 Handler. 처리기를 사용하면 MessagingQueues메시지를 예약하거나 여러 UI 요소를 업데이트하거나 작업을 반복하려는 경우 이점이 있습니다.

AsyncTask실제로는 비슷 Handler하지만 UI 스레드에서 실행되지 않으므로 웹 서비스 가져 오기와 같은 데이터 가져 오기에 좋습니다. 나중에 UI와 상호 작용할 수 있습니다.

Thread그러나 UI와 상호 작용할 수 없으며 더 많은 "기본"스레딩을 제공하며의 모든 추상화를 놓치게됩니다 AsyncTask.

그러나 서비스에서 소켓 연결을 실행하고 싶습니다. 이것이 핸들러 또는 스레드에서 실행되어야합니까, 심지어AsyncTask ? UI 상호 작용이 전혀 필요하지 않습니다. 내가 사용하는 성능면에서 차이가 있습니까?

한편, 문서 는 크게 개선되었습니다.



9
"핸들러는 배경 스레드입니다"-가장 많이 투표 된 답변 중 일부가 그 방향으로 가고있는 것 같습니다. 그러나 그것은 오해입니다. A Handler는 스레드가 아니며 아무것도 실행하지 않습니다. 그것은 단지 수단 안전하게 하나 개의 메시지를 전달하는 스레드 서로 메시지 큐로 스레드 . 따라서 일반적으로 핸들러 를 사용할 수있는 (적어도) 두 개의 스레드를 작성해야 하지만 핸들러는 자체적으로 아무것도 실행할 수 없습니다.
JimmyB

답변:


57

처리기를 사용 하여 Android 백그라운드 처리 에 대한 자습서로서 Vogella 사이트의 AsyncTask 및 로더 는 다음 같이 설명 합니다.

Handler클래스의 스레드에 등록 할 때 사용이 스레드에 데이터를 전송하는 간단한 채널을 제공 할 수있다.

AsyncTask클래스는 백그라운드 프로세스 작성 및 기본 스레드와의 동기화를 캡슐화합니다. 실행중인 작업의 진행률보고도 지원합니다.

a Thread는 기본적으로 개발자가 다음과 같은 단점을 가지고 사용할 수있는 멀티 스레딩의 핵심 요소입니다.

Java 스레드를 사용하는 경우 고유 코드에서 다음 요구 사항을 처리해야합니다.

  • 사용자 인터페이스에 결과를 다시 게시하면 기본 스레드와 동기화
  • 스레드를 취소하기위한 기본값이 없습니다.
  • 기본 스레드 풀링 없음
  • Android에서 구성 변경을 처리하기위한 기본값이 없습니다.

그리고 Android Developer 's ReferenceAsyncTask따르면 :

AsyncTaskUI 스레드를 적절하고 쉽게 사용할 수 있습니다. 이 클래스를 사용하면 스레드 및 / 또는 핸들러를 조작하지 않고도 백그라운드 작업을 수행하고 UI 스레드에 결과를 게시 할 수 있습니다.

AsyncTask헬퍼 클래스 주위를 수 있도록 설계 ThreadHandler 및 일반적인 스레딩 프레임 워크를 구성하지 않습니다. AsyncTasks는 짧은 작업 (최대 몇 초)에 이상적으로 사용되어야합니다. 스레드를 장시간 계속 실행해야하는 경우 java.util.concurrent 패키지에서 제공하는 다양한 API (예 : Executor, ThreadPoolExecutor 및 FutureTask.

2015 년 5 월 업데이트 : 이 주제를 다루는 훌륭한 강의 시리즈를 발견했습니다 .

이것은 구글 검색입니다 : Douglas Schmidt 강의 Android 동시성 및 동기화

YouTube 첫 강의 비디오입니다

이 모든의 일부입니다 안드로이드 프로그래밍 시스템 : CS 282 (2013) 으로부터 밴더빌트 대학 . YouTube 재생 목록 은 다음과 같습니다.

Douglas Schmidt는 훌륭한 강사 인 것 같습니다

중요 사항 :AsyncTask 스레딩 문제를 해결하기 위해 사용 하고자 하는 시점에있는 경우 먼저 보다 적절한 프로그래밍 패턴을 확인ReactiveX/RxAndroid 해야합니다 . 개요를 얻는 데 매우 유용한 자료는 예를 들어 Android 용 RxJava 2 학습 입니다.


4
이 강의 시리즈에서이 링크는 몇 가지 실례로 바로 연결됩니다. youtu.be/4Vue_KuXfCk?t=19m24s
Aggressor

353

우리는 소스 코드를 보면, 우리가 볼 수 AsyncTaskHandler 순수 자바로 작성된 것입니다. (그러나 몇 가지 예외가 있습니다. 그러나 중요한 것은 아닙니다.)

AsyncTask또는에 마법이 없습니다 Handler. 이 수업은 개발자로서 우리의 삶을 더 쉽게 만듭니다.

예를 들어, 프로그램 A가 메소드 A ()를 호출하면 메소드 A ()는 프로그램 A와 다른 스레드에서 실행될 수 있습니다. 다음 코드를 통해 쉽게 확인할 수 있습니다.

Thread t = Thread.currentThread();    
int id = t.getId();

일부 작업에 새 스레드를 사용해야하는 이유는 무엇입니까? 당신은 그것을 구글 할 수 있습니다. 많은 이유, 예 : 무겁고 오래 지속되는 작업 리프팅

그래서, 차이 무엇인가 Thread, AsyncTask그리고는 Handler?

AsyncTaskHandler자바 (내부적으로는을 사용하여 작성됩니다 Thread우리가 할 수있는 모든 있도록) Handler또는 AsyncTask우리는 사용하여 달성 할 수 Thread도 있습니다.

무엇을 할 수 Handler있고AsyncTask 정말 도움이 필요하십니까?

가장 확실한 이유는 호출자 스레드와 작업자 스레드 간의 통신입니다. ( 호출자 스레드 : 일부 작업을 수행하기 위해 작업자 스레드를 호출하는 스레드입니다 . 호출자 스레드는 반드시 UI 스레드 일 필요는 없습니다). 물론 다른 방식으로 두 스레드간에 통신 할 수 있지만 스레드 안전성으로 인해 많은 단점 (및 위험)이 있습니다.

그래서 우리는 Handlerand를 사용해야합니다 AsyncTask. 이 클래스는 대부분의 작업을 수행하므로 재정의 할 메소드 만 알면됩니다.

의 차이 Handler와는 AsyncTask이다 : 사용 AsyncTask하면 발신자 스레드 A는 UI 스레드 . 이것은 안드로이드 문서가 말하는 것입니다 :

AsyncTask를 사용하면 UI 스레드를 적절하고 쉽게 사용할 수 있습니다. 이 클래스를 사용하면 스레드 및 / 또는 핸들러를 조작하지 않고도 백그라운드 작업을 수행하고 UI 스레드에 결과를 게시 할 수 있습니다.

두 가지 사항을 강조하고 싶습니다.

1) UI 스레드를 쉽게 사용할 수 있습니다 (따라서 호출자 스레드가 UI 스레드 인 경우 사용).

2) 핸들러를 조작 할 필요가 없습니다. (의미 : AsyncTask 대신 Handler를 사용할 수 있지만 AsyncTask가 더 쉬운 옵션입니다).

이 게시물에는 아직 말하지 않은 많은 것들이 있습니다. 예를 들어 UI 스레드가 무엇입니까, 왜 더 쉬운 지. 각 클래스의 배후에있는 메소드를 알고 사용해야하며 그 이유를 완전히 이해할 것입니다.

@ : Android 문서를 읽으면 다음이 표시됩니다.

핸들러를 사용하면 스레드의 MessageQueue와 관련된 Message 및 Runnable 객체를 보내고 처리 할 수 ​​있습니다

이 설명은 처음에는 이상하게 보일 수 있습니다. 우리는 각 스레드가 할일 목록과 같은 각 메시지 큐를 가지고 있고 스레드는 각 메시지를 가져 와서 메시지 큐가 비워 질 때까지 (작업을 마치고 잠자리에 든 것처럼) 수행합니다. 그렇게 할 때Handler 통신 호출자 스레드에 메시지를 제공하고 처리를 기다립니다.

복잡한? Handler호출자 스레드와 안전하게 통신 할 수 있다는 것을 기억하십시오 .


4
실제로 AsyncTask를 또한 핸들러와 futuretask을 기반으로, 참조
수밋

AsyncTask는 기본적으로 Handler와 Thread를 기반으로하는 도우미 클래스입니다. developer.android.com/reference/android/os/AsyncTask.html . "AsyncTask는 Thread and Handler에 대한 헬퍼 클래스가되도록 설계되었습니다"문서를보십시오. API1부터 Handler가있는 동안 AsyncTask는 API3에서 릴리스됩니다.
hjchin

52

심층적으로 살펴본 후에는 간단합니다.

AsyncTask:

자바 스레드 모델에 대해 전혀 몰라도 스레드를 사용하는 간단한 방법 입니다. AsyncTask워커 스레드와 메인 스레드에 각각 다양한 콜백을 제공합니다.

다음과 같은 작은 대기 작업에 사용하십시오.

  1. 웹 서비스에서 일부 데이터를 가져 와서 레이아웃 위에 표시합니다.
  2. 데이터베이스 쿼리.
  3. 실행중인 작업이 절대 중첩되지 않는다는 것을 알고있을 때.

Handler:

Android에 응용 프로그램을 설치하면 MAIN UI Thread라는 해당 응용 프로그램에 대한 스레드가 생성됩니다. 모든 활동은 해당 스레드 내에서 실행됩니다. Android 단일 스레드 모델 규칙에 따라 해당 활동 내에 정의 된 다른 스레드의 UI 요소 (비트 맵, 텍스트보기 등)에 직접 액세스 할 수 없습니다.

핸들러를 사용하면 다른 백그라운드 스레드에서 UI 스레드와 다시 통신 할 수 있습니다. 이것은 안드로이드가 다른 스레드가 UI 스레드와 직접 통신하는 것을 허용하지 않으므로 안드로이드에서 유용합니다. 처리기는 스레드의 MessageQueue와 관련된 Message 및 Runnable 객체를 보내고 처리 할 수 ​​있습니다. 각 핸들러 인스턴스는 단일 스레드 및 해당 스레드의 메시지 큐와 연관됩니다. 새 핸들러가 작성되면이를 작성중인 스레드의 스레드 / 메시지 큐에 바인드됩니다.

다음에 가장 적합합니다.

  1. 메시지 큐잉을 할 수 있습니다.
  2. 메시지 스케줄링.

Thread:

이제 스레드에 대해 이야기 할 차례입니다.

스레드는 AsyncTask및 의 부모입니다 Handler. 둘 다 내부적으로 스레드를 사용 하므로 and와 같은 자체 스레드 모델을 만들 수 있지만 Java의 다중 스레드 구현에 대한 지식이 필요합니다 .AsyncTaskHandler


1
실제로 AsyncTask API는 Futures, Handlers 및 Executor로 작성되었습니다. 소스 코드를 참조하십시오 : grepcode.com/file_/repository.grepcode.com/java/ext/…
IgorGanapolsky

22

AsyncTask몇 가지 배경 계산을하고 (옵션 진행 업데이트) UI 스레드에 결과를 게시하는 데 사용됩니다. UI에 관심이 없으므로 a Handler또는Thread 더 적절한 것으로 보입니다.

의 메소드를 Thread사용하여 백그라운드를 생성하고 메인 스레드로 메시지를 다시 전달할 수 있습니다 .Handlerpost


9

안드로이드는 표준 자바 스레드를 지원합니다 . 패키지 " java.util.concurrent" 의 표준 스레드 및 도구를 사용하여 작업을 백그라운드로 수행 할 수 있습니다. 유일한 제한은 백그라운드 프로세스에서 UI를 직접 업데이트 할 수 없다는 것입니다.

백그라운드 작업에서 UI를 업데이트해야하는 경우 일부 Android 특정 클래스를 사용해야합니다. 당신은 클래스 "를 사용할 수 있습니다 android.os.Handler"이 또는 클래스 " AsyncTask"

매니저

Handler” 클래스 는 UI를 업데이트 할 수 있습니다. 핸들은 메시지 수신 및 실행 가능 메소드를 제공합니다. 핸들러를 사용하려면 서브 클래스 handleMessage()를 처리하고 메시지를 처리하도록 대체 해야합니다. 처리하려면 Runable다음 방법을 사용할 수 있습니다 post();. 활동에는 핸들러 인스턴스가 하나만 필요합니다.

당신은 방법을 통해 메시지를 게시 할 수 스레드 sendMessage(Message msg)sendEmptyMessage.

비동기 작업

당신이있는 경우 Activity다운로드 콘텐츠에 대한 어떤 요구를하거나 수행 백그라운드에서 수행 할 수있는 작업은 AsyncTask당신이 반응하는 사용자 인터페이스를 유지하고 사용자에게 그 작업에 대한 진행 상황을 게시 할 수 있습니다.

자세한 내용은 다음 링크를 참조하십시오.

http://mobisys.in/blog/2012/01/android-threads-handlers-and-asynctask-tutorial/

http://www.slideshare.net/HoangNgoBuu/android-thread-handler-and-asynctask


6

Thread:

ThreadUI 스레드에 영향을주지 않으면 서 장기간 실행되는 백그라운드 작업에 새로운 기능 을 사용할 수 있습니다 . Java Thread에서는 UI Thread를 업데이트 할 수 없습니다.

일반 스레드 는 Android 아키텍처에별로 유용하지 않으므로 스레딩을위한 도우미 클래스가 도입되었습니다.

스레딩 성능 문서 페이지 에서 쿼리에 대한 답변을 찾을 수 있습니다 .

처리기 :

A를 Handler사용하면 메시지 및 Runnable스레드와 관련된 객체 를 보내고 처리 할 수 ​​있습니다 MessageQueue. 각 Handler인스턴스는 단일 스레드 및 해당 스레드의 메시지 큐와 연관됩니다.

에 대한 두 가지 주요 용도가 있습니다 Handler.

  1. 메시지 및 실행 가능 파일이 미래의 특정 시점으로 실행되도록 예약합니다.

  2. 자신과 다른 스레드에서 수행 할 작업을 큐에 넣습니다.

AsyncTask :

AsyncTaskUI 스레드를 적절하고 쉽게 사용할 수 있습니다. 이 클래스를 사용하면 스레드 및 / 또는 핸들러를 조작하지 않고도 백그라운드 작업을 수행하고 UI 스레드에 결과를 게시 할 수 있습니다.

단점 :

  1. 기본적으로 앱은 AsyncTask생성 된 모든 개체를 단일 스레드로 푸시합니다 . 따라서 그것들은 직렬 방식으로 실행되며, 메인 스레드와 마찬가지로 특히 긴 작업 패킷이 대기열을 차단할 수 있습니다. 이러한 이유로 AsyncTask를 사용하여 5ms 보다 짧은 작업 항목을 처리하십시오 .

  2. AsyncTask또한 객체는 암시 적 참조 문제의 가장 일반적인 위반자입니다. AsyncTask개체는 명시 적 참조와 관련된 위험도 나타냅니다.

HandlerThread :

장기 실행 스레드 ( 5ms 워크로드에 사용해야하는 AsyncTask와 달리) 에서 작업 블록을 실행하는 전통적인 접근 방식 과 해당 워크 플로우를 수동으로 관리하는 기능 이 필요할 수 있습니다. 핸들러 스레드는 사실상 큐에서 작업을 가져 와서 작동하는 장기 실행 스레드입니다.

ThreadPoolExecutor :

이 클래스는 스레드 그룹 작성을 관리하고 우선 순위를 설정하며 스레드간에 작업이 분배되는 방식을 관리합니다. 워크로드가 증가하거나 감소함에 따라 클래스는 더 많은 스레드를 스핀 업 또는 파괴하여 워크로드에 맞 춥니 다.

작업량이 많고 단일 HandlerThread이 충분하지 않은 경우ThreadPoolExecutor

그러나 서비스에서 소켓 연결을 실행하고 싶습니다. 이것은 핸들러 또는 스레드 또는 AsyncTask에서 실행되어야합니까? UI 상호 작용이 전혀 필요하지 않습니다. 내가 사용하는 성능면에서 차이가 있습니까?

UI 상호 작용이 필요하지 않으므로을 (를) 방문하지 않아도됩니다 AsyncTask. 일반 스레드는별로 유용하지 않으므로 HandlerThread최상의 옵션입니다. 소켓 연결을 유지해야하기 때문에 메인 스레드의 핸들러는 전혀 유용하지 않습니다. 를 작성 HandlerThread하고 얻을 Handler의 루퍼에서 HandlerThread.

 HandlerThread handlerThread = new HandlerThread("SocketOperation");
 handlerThread.start();
 Handler requestHandler = new Handler(handlerThread.getLooper());
 requestHandler.post(myRunnable); // where myRunnable is your Runnable object. 

UI 스레드와 다시 통신하려면 하나 이상의 핸들러를 사용하여 응답을 처리 할 수 ​​있습니다.

final Handler responseHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            //txtView.setText((String) msg.obj);
            Toast.makeText(MainActivity.this,
                    "Foreground task is completed:"+(String)msg.obj,
                    Toast.LENGTH_LONG)
                    .show();
        }
    };

Runnable추가 할 수 있습니다

responseHandler.sendMessage(msg);

구현에 대한 자세한 내용은 다음을 참조하십시오.

안드로이드 : 스레드 토스트


5

제 생각에 스레드는 소켓 연결을 수행하는 가장 효율적인 방법은 아니지만 스레드 실행 측면에서 가장 기능을 제공합니다. 경험상 스레드를 오랫동안 실행하면 장치가 매우 뜨겁고 리소스를 많이 사용하게됩니다. 간단한 while(true)것 조차도 몇 분 안에 전화를 데울 것입니다. UI 상호 작용이 중요하지 않다고 말하면 AsyncTask장기 프로세스를 위해 설계되었으므로 좋을 것 입니다. 이것은 단지 내 의견입니다.

최신 정보

위의 답변을 무시하십시오! 나는 지금보다 안드로이드에서 경험이 훨씬 적었던 2011 년 에이 질문에 대답했습니다. 위의 답변은 오도의 소지가 있으며 잘못된 것으로 간주됩니다. 많은 사람들이 아래에서 저를 시정하는 것에 대해 댓글을 달았으므로 수업을 배웠습니다.

이 스레드에는 다른 더 나은 답변이 있지만 적어도 더 적절한 답변을 드리겠습니다. 일반적인 Java를 사용하는 데 아무런 문제가 없습니다 Thread. 그러나 잘못 구현하는 경우 프로세서를 많이 사용하기 때문에 구현 방법에주의해야합니다 (가장 주목할만한 증상은 장치가 가열 될 수 있음). AsyncTask이는 백그라운드에서 실행하려는 대부분의 작업에 매우 이상적입니다 (일반적인 예는 디스크 I / O, 네트워크 호출 및 데이터베이스 호출입니다). 그러나 AsyncTask사용자가 앱을 닫거나 장치를 대기 상태로 전환 한 후에 계속해야하는 특히 긴 프로세스 에는 s를 사용해서는 안됩니다. 대부분의 경우 UI 스레드에 속하지 않는 모든 항목은에서 처리 할 수 ​​있습니다 AsyncTask.


감사합니다. 실제로 AsyncTasks 대신 Threads를 사용해야하는 이유가 있습니까? 아니면 그것을 사용하는 것이 더 권장됩니까?
Alx

9
@AeroDroid 예제 : "간단한 while (true)"에서는 루프에 절전 상태를 추가하지 않는 한 여기에서 CPU를 페그합니다. 이것은 무한 루프에 해당됩니다. 이 오버 헤드로 인해 CPU 사용량을 줄이려면 루프 끝에서 스레드를 몇 밀리 초 동안 휴면하십시오.
오류 454

1
@ 454 오류-재미있다! 수면 시간에 적절한 숫자를 선택해야한다면 40-80 밀리 초 사이입니까?
Abhijit

6
@Abhijit SDL에서 수행 한 게임 작업에서 단순히 루프에 10ms 절전 모드를 추가하면 유휴 상태에서 99 % CPU에서 ~ 0으로 떨어질 수있었습니다.
454

15
실제로 developer.android.com/reference/android/os/AsyncTask.html 은 "AsyncTask는 SHORT 작업에 이상적으로 사용되어야합니다"라고 말합니다. 또한 실행하지 않고 시스템에서 해제 할 수 있으므로주의해서 사용해야합니다!
type-a1pha

5

AsyncTask백그라운드에서 수행되는 작업을 몇 초 이상 수행하도록 설계되었습니다 (파일 IO 작업과 같은 서버 또는 컴퓨팅 CPU 집약적 작업에서 메가 바이트의 파일 다운로드에는 권장되지 않음). 장기 실행 작업을 실행해야하는 경우 Java 기본 스레드를 사용하는 것이 좋습니다. Java는 필요한 스레드 작업 클래스를 제공합니다. HandlerUI 스레드를 업데이트하는 데 사용 합니다.


2
public class RequestHandler {

    public String sendPostRequest(String requestURL,
                                  HashMap<String, String> postDataParams) {

        URL url;

        StringBuilder sb = new StringBuilder();
        try {
            url = new URL(requestURL);

            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(15000);
            conn.setConnectTimeout(15000);
            conn.setRequestMethod("POST");
            conn.setDoInput(true);
            conn.setDoOutput(true);


            OutputStream os = conn.getOutputStream();
            BufferedWriter writer = new BufferedWriter(
                    new OutputStreamWriter(os, "UTF-8"));
            writer.write(getPostDataString(postDataParams));

            writer.flush();
            writer.close();
            os.close();
            int responseCode = conn.getResponseCode();

            if (responseCode == HttpsURLConnection.HTTP_OK) {
                BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                sb = new StringBuilder();
                String response;
                while ((response = br.readLine()) != null){
                    sb.append(response);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    private String getPostDataString(HashMap<String, String> params) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder();
        boolean first = true;
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (first)
                first = false;
            else
                result.append("&");

            result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
            result.append("=");
            result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
        }

        return result.toString();
    }

}

1

예를 들어 여기에 질문에 대한 답을 시도하겠습니다.

MyImageSearch

MyImageSearch에 대한 설명 - 사용자가 텍스트 입력란에 세부 사항을 입력하고 검색 버튼을 클릭하면 플리커가 제공하는 웹 서비스를 통해 인터넷에서 이미지를 검색합니다 (키 / 비밀 토큰을 얻으려면 등록 만하면됩니다) -검색을 위해 그리드 뷰를로드하는 데 사용할 개별 이미지의 URL을 포함하는 응답으로 HTTP 요청 및 GET JSON 데이터를 다시 보냅니다.

내 구현 - 주 활동에서 AsyncTask를 확장하여 doInBackGround 메소드에서 HTTP 요청을 보내고 JSON 응답을 가져 와서 FlickrAdapter를 통해 GridView를 업데이트하는 데 사용할 FlickrItems의 로컬 ArrayList를 업데이트하는 내부 클래스를 정의합니다. (BaseAdapter를 확장) AsyncTask의 onPostExecute ()에서 adapter.notifyDataSetChanged ()를 호출하여 그리드보기를 다시로드하십시오. 여기서 HTTP 요청은 AsyncTask를 통해 수행 한 차단 호출입니다. 또한 어댑터에 항목을 캐시하여 성능을 높이거나 SDCard에 저장할 수 있습니다. FlickrAdapter에서 팽창시킬 그리드에는 구현시 진행률 표시 줄 및 이미지보기가 포함되어 있습니다. 아래에서 내가 사용한 mainActivity의 코드를 찾을 수 있습니다.

지금 질문에 대한 답변 -개별 이미지를 가져 오기위한 JSON 데이터가 있으면 핸들러 또는 스레드 또는 AsyncTask를 통해 백그라운드에서 이미지를 가져 오는 논리를 구현할 수 있습니다. 여기서 다운로드 한 이미지는 UI / 메인 스레드에 표시되어야하므로 컨텍스트에 액세스 할 수 없으므로 스레드를 그대로 사용할 수는 없습니다. FlickrAdapter에서 내가 생각할 수있는 선택 :

  • 선택 1 : LooperThread [스레드 연장] 작성-이 스레드를 열린 상태로 유지하여 한 스레드에서 이미지를 순차적으로 계속 다운로드 [looper.loop ()]
  • 선택 2 : 스레드 풀을 사용하고 my ImageView에 대한 참조가 포함 된 myHandler를 통해 실행 가능 파일을 게시하지만 그리드보기의보기가 재활용되므로 인덱스 4의 이미지가 인덱스 9에 표시되는 문제가 다시 발생할 수 있습니다. 더 많은 시간이 걸리다]
  • 선택 3 [이것을 사용했습니다] : 스레드 풀을 사용하고 ImageView의 인덱스 및 ImageView 자체와 관련된 데이터를 포함하는 myHandler에 메시지를 보냅니다. 따라서 handleMessage ()를 수행하는 동안 currentIndex가 우리가 다운로드하려고 시도한 이미지.
  • 선택 4 : AsyncTask를 사용하여 백그라운드에서 이미지를 다운로드하십시오.하지만 여기서는 스레드 풀에서 원하는 스레드 수에 액세스 할 수 없으며 다른 Android 버전에 따라 다르지만 선택 3에서는 의식적인 결정을 내릴 수 있습니다. 사용중인 장치 구성에 따라 스레드 풀 크기의.

소스 코드는 다음과 같습니다.

public class MainActivity extends ActionBarActivity {

    GridView imageGridView;
    ArrayList<FlickrItem> items = new ArrayList<FlickrItem>();
    FlickrAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        imageGridView = (GridView) findViewById(R.id.gridView1);
        adapter = new FlickrAdapter(this, items);
        imageGridView.setAdapter(adapter);
    }

    // To avoid a memory leak on configuration change making it a inner class
    class FlickrDownloader extends AsyncTask<Void, Void, Void> {



        @Override
        protected Void doInBackground(Void... params) {
            FlickrGetter getter = new FlickrGetter();

            ArrayList<FlickrItem> newItems = getter.fetchItems();

            // clear the existing array
            items.clear();

            // add the new items to the array
            items.addAll(newItems);

            // is this correct ? - Wrong rebuilding the list view and should not be done in background
            //adapter.notifyDataSetChanged();

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);

            adapter.notifyDataSetChanged();
        }

    }

    public void search(View view) {
        // get the flickr data
        FlickrDownloader downloader = new FlickrDownloader();
        downloader.execute();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

내 대답이 오래되었지만 세부 사항을 이해하는 데 도움이되기를 바랍니다.


비유를위한 모범을 바탕으로 한 설명이 다운 투표 된 이유를 알 수 있을까요?
akshaymani

2
이 주제가 약간 오래되었지만 핵심 개념은 여전히 ​​최신 상태입니다. 내 초기 질문에 전혀 대답하지 않았습니다. 예제를 제공하고 어떻게 작동하는지 설명하지만 질문은 핸들러, asynctask 및 스레드의 차이점을 묻습니다.
Alx

@ 80leaves ok 이제 요점을 알았습니다. 다른 방법을 선택하는 결론에 도달하는 방법에 대해 설명했습니다. 어쨌든, 내가 쓴 것이 올바른지 또는 더 향상 될 수 있는지에 대한 귀하 / 다른 사람들의 의견을 듣고 싶습니다.
akshaymani

1

어느 것이 선택해야하는지에 따라 달라집니다

처리기 는 주로 다른 스레드에서 기본 스레드로 전환하는 데 사용되며 처리기는 실행 가능한 작업을 대기열에 게시하는 루퍼에 연결됩니다. 따라서 이미 다른 스레드에 있고 기본 스레드로 전환하면 비동기 작업 또는 다른 스레드 대신 핸들이 필요합니다

핸들이 스레드를 생성 할 때 루 퍼가 아닌 기본 스레드 이외의 스레드에서 생성 된 처리기가 오류를 발생시키지 않으면 해당 스레드를 lopper로 만들어야합니다.

비동기 작업 는 백그라운드 스레드에서 실행되고 주 스레드에 결과를 제공하는 코드를 몇 초 동안 실행하는 데 사용됩니다. ** * AsyncTask 제한 사항 1. 비동기 작업은 활동 수명주기에 첨부되지 않으며 로더가 작동하지 않는 동안 활동이 중단 되더라도 계속 실행됩니다. 이 제한이 없습니다. 2. 모든 비동기 작업은 실행을 위해 동일한 백그라운드 스레드를 공유하여 앱 성능에도 영향을줍니다.

백그라운드 작업에도 앱에서 스레드 가 사용되지만 기본 스레드에서 다시 호출되지 않습니다. 요구 사항이 하나의 스레드 대신 일부 스레드에 적합하고 작업을 여러 번 제공 해야하는 경우 스레드 풀 실행 프로그램이 더 좋습니다. 예 : 글라이드와 같은 여러 URL에서 이미지를로드해야합니다.


0

앱을 시작하면 코드를 실행하는 프로세스가 생성됩니다. 컴퓨팅 리소스를 효율적으로 사용하기 위해 프로세스 내에서 스레드를 시작하여 한 번에 여러 작업을 실행할 수 있습니다. 따라서 스레드를 사용하면 유휴 시간없이 CPU를 효율적으로 활용하여 효율적인 앱을 구축 할 수 있습니다.

Android에서 모든 구성 요소는 기본 스레드라는 단일 스레드에서 실행됩니다. Android 시스템은 작업을 대기열에 놓고 메인 스레드에서 하나씩 실행합니다. 장시간 실행되는 작업이 실행되면 앱이 응답하지 않습니다.

이를 방지하기 위해 작업자 스레드를 만들고 백그라운드 또는 오래 실행되는 작업을 실행할 수 있습니다.

매니저

안드로이드는 단일 스레드 모델을 사용하기 때문에 UI 구성 요소는 스레드로부터 안전하지 않은 것으로 생성됩니다. 즉, 생성 된 스레드 만 액세스해야합니다. 즉, UI 구성 요소는 기본 스레드에서만 업데이트되어야합니다. UI 구성 요소가 기본 스레드에서 실행되면 작업자 스레드에서 실행되는 작업은 UI 구성 요소를 수정할 수 없습니다. Handler가 그림에 나오는 곳입니다. Looper를 사용하여 처리기는 새 스레드 또는 기존 스레드에 연결하고 연결된 스레드에서 포함 된 코드를 실행할 수 있습니다.

핸들러는 스레드 간 통신을 가능하게합니다. 핸들러를 사용하면 백그라운드 스레드가 결과를 전송할 수 있으며 메인 스레드에 연결된 핸들러는 메인 스레드의 UI 구성 요소를 업데이트 할 수 있습니다.

비동기 작업

안드로이드가 제공하는 AsyncTask는 스레드와 핸들러를 모두 사용하여 백그라운드에서 간단한 작업을 실행하고 백그라운드 스레드에서 메인 스레드로 결과를 쉽게 업데이트합니다.

예를 들어 안드로이드 스레드, 핸들러, asynctask 및 스레드 풀 을 참조하십시오 .


-1

Handler-스레드 간의 통신 매체입니다. 안드로이드에서는 주로 핸들러를 통해 메시지를 작성하고 보내서 메인 스레드와 통신하는 데 사용됩니다

AsyncTask-백그라운드 스레드에서 오래 실행되는 응용 프로그램을 수행하는 데 사용됩니다. n으로AsyncTask 을 백그라운드 스레드에서 작업을 수행하고 응용 프로그램의 기본 스레드에서 결과를 얻을 수 있습니다.

Thread-동시성 및 최대 CPU 사용률을 달성하기위한 경량 프로세스입니다. 안드로이드에서는 스레드를 사용하여 앱의 UI를 건드리지 않는 활동을 수행 할 수 있습니다

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