Szukaj…


Parametry

Parametr Detale
Params typ parametrów wysyłanych do zadania po wykonaniu.
Postęp rodzaj jednostek postępu opublikowanych podczas obliczeń w tle
Wynik rodzaj wyniku obliczeń w tle.

Podstawowe użycie

W działaniach i usługach Androida większość połączeń zwrotnych jest uruchamiana w głównym wątku . Ułatwia to aktualizację interfejsu użytkownika, ale wykonywanie zadań obciążających procesor lub operacje we / wy w głównym wątku może spowodować, że interfejs użytkownika zostanie wstrzymany i przestanie odpowiadać ( oficjalna dokumentacja dotycząca tego, co się wtedy stanie).

Możesz temu zaradzić, umieszczając cięższe zadania w tle.

Jednym ze sposobów na to jest użycie AsyncTask , który zapewnia platformę ułatwiającą łatwe korzystanie z wątku w tle, a także wykonywanie zadań wątku interfejsu użytkownika przed, w trakcie i po zakończeniu wątku w tle.

Metody, które można zastąpić podczas rozszerzania AsyncTask :

  • onPreExecute() : wywoływany w wątku interfejsu użytkownika przed wykonaniem zadania
  • doInBackground() : wywoływany w wątku tła natychmiast po zakończeniu wykonywania onPreExecute() .
  • onProgressUpdate() : wywoływany w wątku interfejsu użytkownika po wywołaniu publishProgress(Progress...) .
  • onPostExecute() : wywoływany w wątku interfejsu użytkownika po zakończeniu obliczeń w tle

Przykład

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.");
        }
    }

}

Stosowanie:

MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);

lub po prostu:

new MyCustomAsyncTask().execute(userSuppliedFilename);

Uwaga

Definiując AsyncTask , możemy przekazać trzy typy między nawiasami < > .
Zdefiniowane jako <Params, Progress, Result> (patrz sekcja Parametry )

W poprzednim przykładzie użyliśmy typów <File, Void, String> :

AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String

Void jest używana, gdy chcesz oznaczyć typ jako nieużywany.

Zauważ, że nie możesz przekazać prymitywnych typów (tj. int , float i 6 innych) jako parametrów. W takich przypadkach powinieneś przekazać ich klasy otoki , np. Integer zamiast int lub Float zamiast float .

Cykl życia AsyncTask i aktywności

AsyncTasks nie śledzą cyklu życia instancji działania. Jeśli uruchomisz AsyncTask w działaniu i obrócisz urządzenie, działanie zostanie zniszczone i zostanie utworzona nowa instancja. Ale AsyncTask nie umrze. Będzie żył, dopóki się nie skończy.

Rozwiązanie: AsyncTaskLoader

Jedna podklasa ładowarki jest AsyncTaskLoader. Ta klasa wykonuje tę samą funkcję co AsyncTask, ale znacznie lepiej. Może łatwiej obsługiwać zmiany konfiguracji działania i zachowuje się w cyklach życia fragmentów i działań. Zaletą jest to, że AsyncTaskLoader może być używany w każdej sytuacji, w której używany jest AsyncTask. Za każdym razem, gdy dane muszą zostać załadowane do pamięci, aby obsłużyć działanie / fragment, AsyncTaskLoader może wykonać to zadanie lepiej.

Anulowanie zadania asynchronicznego

YourAsyncTask task = new YourAsyncTask();
task.execute();
task.cancel();

To nie kończy twojego zadania, jeśli było w toku, po prostu ustawia anulowaną flagę, którą można sprawdzić, sprawdzając wartość isCancelled() przez isCancelled() (zakładając, że twój kod jest aktualnie uruchomiony), wykonując następujące czynności:

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;
            }
        }
    }
}

Uwaga

Jeśli AsyncTask zostanie anulowane podczas wykonywania doInBackground(Params... params) wówczas metoda onPostExecute(Result result) NIE zostanie wywołana po doInBackground(Params... params) . Zamiast tego onCancelled(Result result) aby wskazać, że zadanie zostało anulowane podczas wykonywania.

Postęp publikowania

Czasami musimy zaktualizować postęp obliczeń wykonanych przez AsyncTask . Postęp ten może być reprezentowany przez ciąg, liczbę całkowitą itp. Aby to zrobić, musimy użyć dwóch funkcji. Najpierw musimy ustawić funkcję onProgressUpdate której typ parametru jest taki sam, jak parametr drugiego typu w naszym AsyncTask .

class YourAsyncTask extends AsyncTask<URL, Integer, Long> {
    @Override
    protected void onProgressUpdate(Integer... args) {
        setProgressPercent(args[0])
    }
}

Po drugie, musimy koniecznie użyć funkcji publishProgress w funkcji doInBackground , i to wszystko, poprzednia metoda wykona całą pracę.

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;
 }

Pobierz obraz za pomocą AsyncTask na Androida

W tym samouczku wyjaśniono, jak pobrać obraz za pomocą AsyncTask na Androida. Poniższy przykład pobierania obrazu pokazuje pasek postępu podczas pobierania.

Zrozumienie Androida AsyncTask

Zadanie asynchroniczne umożliwia wdrożenie MultiThreading bez brudzenia rąk w wątkach. AsyncTask umożliwia prawidłowe i łatwe korzystanie z wątku interfejsu użytkownika. Umożliwia wykonywanie operacji w tle i przekazywanie wyników w wątku interfejsu użytkownika. Jeśli robisz coś izolowanego związanego z interfejsem użytkownika, na przykład pobierasz dane do przedstawienia na liście, skorzystaj z AsyncTask.

  • Z funkcji AsyncTasks najlepiej korzystać w przypadku krótkich operacji (maksymalnie kilka sekund).
  • Zadanie asynchroniczne jest zdefiniowane przez 3 typy ogólne, o nazwie Params, Progress and Result, oraz 4 kroki, o onPreExecute() , doInBackground() , onProgressUpdate() i onPostExecute() .
  • W onPreExecute() możesz zdefiniować kod, który należy wykonać przed rozpoczęciem przetwarzania w tle.
  • doInBackground ma kod, który należy wykonać w tle, tutaj w doInBackground() możemy wysyłać wyniki do wątku zdarzenia wielokrotnie za pomocą metody PublProgress (), aby powiadomić, że przetwarzanie w tle zostało zakończone, możemy po prostu zwrócić wyniki.
  • onProgressUpdate() odbiera aktualizacje postępu z metody doInBackground() , która jest publikowana za publishProgress() metody publishProgress() , i ta metoda może użyć tej aktualizacji postępu do aktualizacji wątku zdarzenia
  • onPostExecute() obsługuje wyniki zwrócone przez doInBackground() .
  • Stosowane typy ogólne to
    • Parametry, typ parametrów wysyłanych do zadania po wykonaniu
    • Postęp, rodzaj jednostek postępu opublikowanych podczas obliczeń w tle.
    • Wynik, typ wyniku obliczenia w tle.
  • Jeśli zadanie asynchroniczne nie korzysta z żadnych typów, można je oznaczyć jako Typ pustki.
  • Uruchomione zadanie asynchroniczne można anulować, wywołując metodę cancel(boolean) .

Pobieranie obrazu za pomocą Android AsyncTask

twój układ .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>

klasa .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;
        }
    }
}

Ponieważ obecnie nie ma pola komentarza dla przykładów (lub go nie znalazłem lub nie mam na to pozwolenia), oto komentarz na ten temat:

To dobry przykład tego, co można zrobić za pomocą AsyncTask.

Jednak przykład ma obecnie problemy z

  • możliwe wycieki pamięci
  • awaria aplikacji, jeśli obrót ekranu nastąpił na krótko przed zakończeniem zadania asynchronicznego.

Szczegółowe informacje:

Przekaż aktywność jako Słaby Odniesienie, aby uniknąć wycieków pamięci

Często zdarza się, że AsyncTask wymaga odwołania do działania, które go wywołało.

Jeśli AsyncTask jest wewnętrzną klasą działania, możesz bezpośrednio do niego odwoływać i dowolne zmienne / metody składowe.

Jeśli jednak AsyncTask nie jest wewnętrzną klasą działania, konieczne będzie przekazanie odwołania do działania do AsyncTask. Po wykonaniu tej czynności jednym potencjalnym problemem, który może wystąpić, jest to, że AsyncTask zachowa odwołanie do działania, dopóki AsyncTask nie zakończy pracy w wątku w tle. Jeśli działanie zostanie zakończone lub zabite przed zakończeniem pracy wątku AsyncTask w tle, AsyncTask nadal będzie mieć odniesienie do działania, a zatem nie będzie można go wyrzucać.

W rezultacie spowoduje to wyciek pamięci.

Aby temu zapobiec, użyj WeakReference w AsyncTask zamiast bezpośredniego odniesienia do działania.

Oto przykład AsyncTask wykorzystujący 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();
        }
    }
} 

Wywoływanie zadania AsyncTask z działania:

new MyAsyncTask(this).execute("param1", "param2");

Wywoływanie AsyncTask z fragmentu:

new MyAsyncTask(getActivity()).execute("param1", "param2");

Kolejność wykonania

Po raz pierwszy AsyncTasks były wykonywane szeregowo w jednym wątku w tle. Począwszy od DONUT , zmieniono to na pulę wątków, umożliwiając równoległe wykonywanie wielu zadań. Począwszy od HONEYCOMB , zadania są wykonywane w jednym wątku, aby uniknąć typowych błędów aplikacji spowodowanych równoległym wykonywaniem.

Jeśli naprawdę chcesz wykonywać równolegle, możesz wywołać executeOnExecutor(java.util.concurrent.Executor, Object[]) pomocą THREAD_POOL_EXECUTOR .

SERIAL_EXECUTOR -> Executor wykonujący zadania pojedynczo w kolejności szeregowej.

THREAD_POOL_EXECUTOR -> Executor, którego można używać do równoległego wykonywania zadań.

próbka:

Task task = new Task();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
    task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
    task.execute(data);

AsyncTask: wykonanie szeregowe i równoległe wykonanie zadania

AsyncTask jest klasą abstrakcyjną i nie dziedziczy klasy Thread . Ma abstrakcyjną metodę doInBackground(Params... params) , która jest nadpisywana w celu wykonania zadania. Ta metoda jest wywoływana z AsyncTask.call() .

Moduł wykonujący jest częścią pakietu java.util.concurrent .

Ponadto AsyncTask zawiera 2 Executor

THREAD_POOL_EXECUTOR

Używa wątków roboczych do równoległego wykonywania zadań.

public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);

SERIAL_EXECUTOR

Wykonuje zadanie szeregowo, tzn. Jeden po drugim.

private static class SerialExecutor implements Executor { }

Oba moduły Executorstatyczne , dlatego istnieje tylko jeden obiekt THREAD_POOL_EXECUTOR i jeden obiekt SerialExecutor , ale można utworzyć kilka obiektów AsyncTask .

Dlatego jeśli spróbujesz wykonać wiele zadań w tle przy użyciu domyślnego SerialExecutor ( SerialExecutor ), zadanie to zostanie umieszczone w kolejce i wykonane szeregowo.

Jeśli spróbujesz wykonać wiele zadań w tle za pomocą THREAD_POOL_EXECUTOR , zostaną one wykonane równolegle.

Przykład:

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");
        }
    }
}

Wykonaj Kliknij kilka razy przycisk, aby rozpocząć zadanie i zobaczyć wynik.

Zadanie wykonane w puli wątków (1)

Każde zadanie zajmuje 1000 ms.

W czasie t = 36s zadania 2, 3 i 4 są umieszczone w kolejce i rozpoczęły wykonywanie również dlatego, że są wykonywane równolegle.

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
----------

Komentarz Task Executed in thread pool (1) i odkomentowanie Task executed Serially (2).

Wykonaj Kliknij kilka razy przycisk, aby rozpocząć zadanie i zobaczyć wynik.

Wykonuje zadanie szeregowo, dlatego każde zadanie jest uruchamiane po zakończeniu bieżącego zadania. Dlatego po zakończeniu wykonywania zadania 1 tylko zadanie 2 zaczyna działać w tle. Nawzajem.

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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow