Android
AsyncTask
수색…
매개 변수
매개 변수 | 세부 |
---|---|
Params | 실행시 태스크에 송신 된 매개 변수의 유형. |
진행 | 백그라운드 계산 중에 발행 된 진행 단위의 유형 |
결과 | 백그라운드 계산의 결과의 형태 |
기본 사용법
Android 활동 및 서비스 에서 대부분의 콜백은 기본 스레드 에서 실행됩니다. 이것은 내가 주 스레드에서 / O가 많은 작업이 UI가 응답하지 (일시 정지 및 질 수 있습니다 간단 UI를 업데이트 할 수 있지만, 프로세서 - 또는를 실행하는 공식 문서 다음 어떻게되는지에 대한 참조).
이 무거운 작업을 백그라운드 스레드에 넣음으로써이를 해결할 수 있습니다.
이 작업을 수행하는 한 가지 방법은 AsyncTask를 사용하는 것입니다.이 AsyncTask 는 백그라운드 스레드를 쉽게 사용할 수있는 프레임 워크를 제공하고 백그라운드 스레드가 작업을 완료하기 전, 도중 및 후에 UI 스레드 작업을 수행합니다.
AsyncTask
확장 할 때 재정의 할 수있는 메서드 :
-
onPreExecute()
: 작업이 실행되기 전에 UI 스레드 에서 호출됩니다. -
doInBackground()
:onPreExecute()
가 실행을onPreExecute()
직후 백그라운드 스레드 에서 호출됩니다. -
onProgressUpdate()
:publishProgress(Progress...)
호출 후 UI 스레드 에서 호출됩니다. -
onPostExecute()
: 백그라운드 계산이 끝난 후에 UI 스레드 에서 호출됩니다.
예
public class MyCustomAsyncTask extends AsyncTask<File, Void, String> {
@Override
protected void onPreExecute(){
// This runs on the UI thread before the background thread executes.
super.onPreExecute();
// Do pre-thread tasks such as initializing variables.
Log.v("myBackgroundTask", "Starting Background Task");
}
@Override
protected String doInBackground(File... params) {
// Disk-intensive work. This runs on a background thread.
// Search through a file for the first line that contains "Hello", and return
// that line.
try (Scanner scanner = new Scanner(params[0])) {
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
publishProgress(); // tell the UI thread we made progress
if (line.contains("Hello")) {
return line;
}
}
return null;
}
}
@Override
protected void onProgressUpdate(Void...p) {
// Runs on the UI thread after publishProgress is invoked
Log.v("Read another line!")
}
@Override
protected void onPostExecute(String s) {
// This runs on the UI thread after complete execution of the doInBackground() method
// This function receives result(String s) returned from the doInBackground() method.
// Update UI with the found string.
TextView view = (TextView) findViewById(R.id.found_string);
if (s != null) {
view.setText(s);
} else {
view.setText("Match not found.");
}
}
}
용법:
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);
또는 간단히 :
new MyCustomAsyncTask().execute(userSuppliedFilename);
노트
AsyncTask
정의 할 때 < >
대괄호 사이에 세 가지 유형을 전달할 수 있습니다.
<Params, Progress, Result>
로 정의됩니다 ( 매개 변수 섹션 참조 ).
앞의 예제에서는 <File, Void, String>
형식을 사용했습니다.
AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String
Void
는 유형을 사용하지 않음으로 표시하려는 경우에 사용됩니다.
매개 변수로 기본 유형 (예 : int
, float
및 기타 6 개)을 전달할 수 없습니다. 이러한 경우에, 당신은 그들의 통과해야 래퍼 클래스 , 예를 들어, Integer
대신 int
, 또는 Float
대신 float
.
비동기 태스크 및 활동 라이프 사이클
AsyncTasks는 Activity 인스턴스의 라이프 사이클을 따르지 않습니다. 액티비티 내에서 AsyncTask를 시작하고 장치를 회전하면 액티비티가 삭제되고 새 인스턴스가 생성됩니다. 그러나 AsyncTask는 죽지 않을 것입니다. 그것은 완료 될 때까지 계속 살 것입니다.
솔루션 : AsyncTaskLoader
Loader의 한 하위 클래스는 AsyncTaskLoader입니다. 이 클래스는 AsyncTask와 동일한 기능을 수행하지만 훨씬 더 좋습니다. 활동 구성 변경 사항을보다 쉽게 처리 할 수 있으며 조각 및 활동의 수명주기 내에서 작동합니다. 좋은 점은 AsyncTaskLoader는 AsyncTask가 사용되는 모든 상황에서 사용될 수 있다는 것입니다. Activity / Fragment가 처리 할 수 있도록 언제든지 데이터를 메모리에로드해야하는 경우 AsyncTaskLoader가 작업을 더 잘 수행 할 수 있습니다.
AsyncTask 취소
YourAsyncTask task = new YourAsyncTask();
task.execute();
task.cancel();
이것은 진행중인 경우 작업을 멈추지 않고 isCancelled()
의 반환 값을 검사하여 확인할 수있는 취소 된 플래그를 설정합니다 (코드가 현재 실행 중이라고 가정).
class YourAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
while(!isCancelled()) {
... doing long task stuff
//Do something, you need, upload part of file, for example
if (isCancelled()) {
return null; // Task was detected as canceled
}
if (yourTaskCompleted) {
return null;
}
}
}
}
노트
동안 AsyncTask를 취소하는 경우 doInBackground(Params... params)
여전히 다음 실행 방법 onPostExecute(Result result)
이후에 호출되지 않습니다 doInBackground(Params... params)
으로 돌아갑니다. AsyncTask는 대신 onCancelled(Result result)
를 호출하여 실행 중에 작업이 취소되었음을 나타냅니다.
출판 진행
때로는 AsyncTask
의해 수행 된 계산 진행 상황을 업데이트해야합니다. 이 진도는 문자열, 정수 등으로 표현 될 수 있습니다. 이렇게하려면 두 가지 함수를 사용해야합니다. 먼저, AsyncTask
의 두 번째 유형 매개 변수와 동일한 매개 변수 유형을 가진 onProgressUpdate
함수를 설정해야합니다.
class YourAsyncTask extends AsyncTask<URL, Integer, Long> {
@Override
protected void onProgressUpdate(Integer... args) {
setProgressPercent(args[0])
}
}
둘째, 우리는 반드시 doInBackground
함수에서 publishProgress
함수를 사용해야 publishProgress
. 모든 것이기 때문에 이전 메서드는 모든 작업을 수행합니다.
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
Android에서 AsyncTask를 사용하여 이미지 다운로드
이 튜토리얼은 Android에서 AsyncTask를 사용하여 이미지를 다운로드하는 방법을 설명합니다. 아래의 예는 다운로드 중에 진행률 표시 줄을 보여 주면서 이미지를 다운로드합니다.
Android AsyncTask 이해하기
비동기 작업을 사용하면 손으로 스레드를 더럽 히지 않고도 MultiThreading을 구현할 수 있습니다. AsyncTask를 사용하면 UI 스레드를 적절하고 쉽게 사용할 수 있습니다. 백그라운드 작업을 수행하고 UI 스레드에서 결과를 전달할 수 있습니다. UI와 관련하여 고립 된 무언가를하고 있다면, 예를 들어 목록에있는 데이터를 다운로드하는 것과 같이 AsyncTask를 사용하십시오.- AsyncTasks는 이상적인 경우 짧은 작업에 사용되어야합니다 (최대 몇 초).
- 비동기 작업은 Params, Progress and Result 및
onPreExecute()
,doInBackground()
,onProgressUpdate()
및onPostExecute()
라는 네 단계라는 3 가지 일반 유형으로 정의됩니다. -
onPreExecute()
백그라운드 처리가 시작되기 전에 실행되어야하는 코드를 정의 할 수 있습니다. - doInBackground는 백그라운드에서 실행될 필요가있는 코드를 가지고 있습니다. 여기
doInBackground()
에서 publishProgress () 메소드로 여러 번 결과를 보낼 수 있습니다. 백그라운드 처리가 완료되었음을 알리기 위해 결과를 간단하게 반환 할 수 있습니다. -
onProgressUpdate()
메서드는publishProgress()
메서드를 통해 게시 된doInBackground()
메서드에서 진행률 업데이트를publishProgress()
메서드는이 진행률 업데이트를 사용하여 이벤트 스레드를 업데이트 할 수 있습니다 -
onPostExecute()
메소드는doInBackground()
메소드가 리턴 한 결과를 처리합니다. - 사용 된 제네릭 유형은 다음과 같습니다.
- Params, 실행시 태스크로 보내지는 매개 변수의 유형
- 진행률, 백그라운드 계산 중에 게시 된 진행 단위의 유형입니다.
- 결과, 백그라운드 계산 결과의 유형.
- 비동기 작업이 유형을 사용하지 않는 경우 Void 유형으로 표시 될 수 있습니다.
- 실행중인 비동기 태스크는
cancel(boolean)
메소드를 호출하여 취소 할 수 있습니다.
Android AsyncTask를 사용하여 이미지 다운로드
.xml 레이아웃
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/downloadButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Here to Download" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="Your image will appear here" />
</LinearLayout>
.java 클래스
package com.javatechig.droid;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class ImageDownladerActivity extends Activity {
private ImageView downloadedImg;
private ProgressDialog simpleWaitDialog;
private String downloadUrl = "http://www.9ori.com/store/media/images/8ab579a656.jpg";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.asynch);
Button imageDownloaderBtn = (Button) findViewById(R.id.downloadButton);
downloadedImg = (ImageView) findViewById(R.id.imageView);
imageDownloaderBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new ImageDownloader().execute(downloadUrl);
}
});
}
private class ImageDownloader extends AsyncTask {
@Override
protected Bitmap doInBackground(String... param) {
// TODO Auto-generated method stub
return downloadBitmap(param[0]);
}
@Override
protected void onPreExecute() {
Log.i("Async-Example", "onPreExecute Called");
simpleWaitDialog = ProgressDialog.show(ImageDownladerActivity.this,
"Wait", "Downloading Image");
}
@Override
protected void onPostExecute(Bitmap result) {
Log.i("Async-Example", "onPostExecute Called");
downloadedImg.setImageBitmap(result);
simpleWaitDialog.dismiss();
}
private Bitmap downloadBitmap(String url) {
// initilize the default HTTP client object
final DefaultHttpClient client = new DefaultHttpClient();
//forming a HttpGet request
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
//check 200 OK for success
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode +
" while retrieving bitmap from " + url);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
// getting contents from the stream
inputStream = entity.getContent();
// decoding stream data back into image Bitmap that android understands
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// You Could provide a more explicit error message for IOException
getRequest.abort();
Log.e("ImageDownloader", "Something went wrong while" +
" retrieving bitmap from " + url + e.toString());
}
return null;
}
}
}
현재 예제에 대한 주석 필드가 없기 때문에 (또는 찾지 못했거나 권한이 없습니다) 여기에 대한 몇 가지 코멘트가 있습니다 :
이것은 AsyncTask로 수행 할 수있는 좋은 예입니다.
그러나이 예제는 현재
- 메모리 누수 가능성
- 비동기 작업이 완료되기 직전에 화면이 회전했다면 앱이 다운됩니다.
자세한 내용은 다음을 참조하십시오.
- WeakReference로 Activity를 전달하여 메모리 누수를 방지합니다.
- http://stackoverflow.com/documentation/android/117/asynctask/5377/possible-problems-with-inner-async-tasks
- AsyncTask로 활동 유출 방지
WeakReference로 Activity를 전달하여 메모리 누수를 방지합니다.
AsyncTask는 호출 한 Activity에 대한 참조를 요구하는 것이 일반적입니다.
AsyncTask가 Activity의 내부 클래스 인 경우 AsyncTask 및 해당 멤버 변수 / 메서드를 직접 참조 할 수 있습니다.
그러나 AsyncTask가 Activity의 내부 클래스가 아니면 AsyncTask에 대한 Activity 참조를 전달해야합니다. 이를 수행 할 때 발생할 수있는 잠재적 인 문제점 중 하나는 AsyncTask가 백그라운드 스레드에서 작업을 완료 할 때까지 AsyncTask가 활동 참조를 유지한다는 것입니다. AsyncTask의 백그라운드 스레드 작업이 완료되기 전에 Activity가 완료되거나 종료되면 AsyncTask는 여전히 Activity에 대한 참조를 가지므로 가비지 수집 될 수 없습니다.
따라서 메모리 누수가 발생합니다.
이러한 일이 발생하지 않도록하려면 Activity에 직접 참조하는 대신 AsyncTask에서 WeakReference 를 사용하십시오.
다음은 WeakReference를 사용하는 비동기 태스크 예제입니다.
private class MyAsyncTask extends AsyncTask<String, Void, Void> {
private WeakReference<Activity> mActivity;
public MyAsyncTask(Activity activity) {
mActivity = new WeakReference<Activity>(activity);
}
@Override
protected void onPreExecute() {
final Activity activity = mActivity.get();
if (activity != null) {
....
}
}
@Override
protected Void doInBackground(String... params) {
//Do something
String param1 = params[0];
String param2 = params[1];
return null;
}
@Override
protected void onPostExecute(Void result) {
final Activity activity = mActivity.get();
if (activity != null) {
activity.updateUI();
}
}
}
활동에서 AsyncTask 호출 :
new MyAsyncTask(this).execute("param1", "param2");
조각에서 AsyncTask 호출 :
new MyAsyncTask(getActivity()).execute("param1", "param2");
실행 명령
처음 소개되었을 때 AsyncTasks
는 단일 백그라운드 스레드에서 순차적으로 실행되었습니다. DONUT
시작하여 여러 스레드가 병렬로 작동 할 수 있도록 스레드 풀로 변경되었습니다. HONEYCOMB
부터는 병렬 실행으로 인한 공통 응용 프로그램 오류를 피하기 위해 단일 스레드에서 작업이 실행됩니다.
병렬 실행을 진정으로 원하면 THREAD_POOL_EXECUTOR
하여 executeOnExecutor(java.util.concurrent.Executor, Object[])
를 호출 할 수 있습니다.
SERIAL_EXECUTOR -> 한 번에 하나씩 작업을 연속적으로 실행하는 Executor.
THREAD_POOL_EXECUTOR -> 작업을 병렬로 실행하는 데 사용할 수있는 실행 프로그램입니다.
샘플 :
Task task = new Task();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
task.execute(data);
AsyncTask : 태스크의 직렬 실행 및 병렬 실행
AsyncTask는 추상 클래스이며 Thread
클래스를 상속하지 않습니다. 그것은 추상적 인 메소드 doInBackground(Params... params)
가지며, 이것은 작업을 수행하기 위해 오버라이드됩니다. 이 메서드는 AsyncTask.call()
에서 호출됩니다.
Executor는 java.util.concurrent
패키지의 일부입니다.
또한 AsyncTask에는 2 개의 Executor
가 있습니다.
THREAD_POOL_EXECUTOR
작업자 스레드를 사용하여 작업을 병렬로 실행합니다.
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
SERIAL_EXECUTOR
작업을 순차적으로, 즉 하나씩 차례로 실행합니다.
private static class SerialExecutor implements Executor { }
두 Executor
는 정적 이므로 하나의 THREAD_POOL_EXECUTOR
및 하나의 SerialExecutor
객체가 있지만 여러 개의 AsyncTask
객체를 만들 수 있습니다.
따라서 기본 Executor ( SerialExecutor
)를 사용하여 여러 백그라운드 작업을 수행하려고하면 이러한 작업이 대기열에 포함되어 연속적으로 실행됩니다.
THREAD_POOL_EXECUTOR
여러 백그라운드 작업을 수행하려고하면 병렬로 실행됩니다.
예:
public class MainActivity extends Activity {
private Button bt;
private int CountTask = 0;
private static final String TAG = "AsyncTaskExample";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
BackgroundTask backgroundTask = new BackgroundTask ();
Integer data[] = { ++CountTask, null, null };
// Task Executed in thread pool ( 1 )
backgroundTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, data);
// Task executed Serially ( 2 )
// Uncomment the below code and comment the above code of Thread
// pool Executor and check
// backgroundTask.execute(data);
Log.d(TAG, "Task = " + (int) CountTask + " Task Queued");
}
});
}
private class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {
int taskNumber;
@Override
protected Integer doInBackground(Integer... integers) {
taskNumber = integers[0];
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d(TAG, "Task = " + taskNumber + " Task Running in Background");
publishProgress(taskNumber);
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(Integer aLong) {
super.onPostExecute(aLong);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.d(TAG, "Task = " + (int) values[0]
+ " Task Execution Completed");
}
}
}
수행 버튼을 여러 번 클릭하여 작업을 시작하고 결과를 봅니다.
스레드 풀 (1)에서 실행 된 작업
각 작업은 완료하는 데 1000ms가 걸립니다.
t = 36s에서 작업 2, 3 및 4는 대기열에 들어가고 동시에 실행되기 때문에 실행되기 시작합니다.
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Queued
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Running in Background
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Queued
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Running in Background
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Queued
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Running in Background
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Queued
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Running in Background
08-02 19:48:**36.815**: D/AsyncTaskExample(11693): Task = 1 Task Execution Completed
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Queued
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Running in Background
08-02 19:48:37.025: D/AsyncTaskExample(11693): Task = 2 Task Execution Completed
08-02 19:48:37.165: D/AsyncTaskExample(11693): Task = 3 Task Execution Completed
----------
주석 Task Executed in thread pool
(1)에서 Task executed Serially
주석 처리를 제거합니다 (2).
수행 버튼을 여러 번 클릭하여 작업을 시작하고 결과를 봅니다.
순차적으로 작업을 실행하므로 현재 작업이 완료되면 모든 작업이 시작됩니다. 따라서 작업 1의 실행이 완료되면 작업 2 만 백그라운드에서 실행되기 시작합니다. 그 반대입니다.
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Queued
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Running in Background
08-02 19:42:57.675: D/AsyncTaskExample(10299): Task = 2 Task Queued
08-02 19:42:57.835: D/AsyncTaskExample(10299): Task = 3 Task Queued
08-02 19:42:58.005: D/AsyncTaskExample(10299): Task = 4 Task Queued
08-02 19:42:58.155: D/AsyncTaskExample(10299): Task = 5 Task Queued
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 1 Task Execution Completed
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 2 Task Running in Background
08-02 19:42:58.755: D/AsyncTaskExample(10299): Task = 6 Task Queued
08-02 19:42:59.295: D/AsyncTaskExample(10299): Task = 7 Task Queued
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 2 Task Execution Completed
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 3 Task Running in Background
08-02 19:43:00.035: D/AsyncTaskExample(10299): Task = 8 Task Queued
08-02 19:43:00.505: D/AsyncTaskExample(10299): Task = 3 Task Execution Completed
08-02 19:43:**00.505**: D/AsyncTaskExample(10299): Task = 4 Task Running in Background
08-02 19:43:**01.505**: D/AsyncTaskExample(10299): Task = 4 Task Execution Completed
08-02 19:43:**01.515**: D/AsyncTaskExample(10299): Task = 5 Task Running in Background
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 5 Task Execution Completed
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 6 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 7 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 6 Task Execution Completed
08-02 19:43:04.515: D/AsyncTaskExample(10299): Task = 8 Task Running in Background
08-02 19:43:**04.515**: D/AsyncTaskExample(10299): Task = 7 Task Execution Completed