수색…


매개 변수

매개 변수 세부
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를 전달하여 메모리 누수를 방지합니다.

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


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow