Ricerca…


Parametri

Parametro Dettagli
Parametri il tipo di parametri inviati all'attività al momento dell'esecuzione.
Progresso il tipo di unità di progresso pubblicate durante il calcolo dello sfondo
Risultato il tipo del risultato del calcolo dello sfondo.

Uso di base

In Attività e servizi Android, la maggior parte dei callback vengono eseguiti sul thread principale . Ciò semplifica l'aggiornamento dell'interfaccia utente, ma l'esecuzione di attività gravose di processore o I / O sul thread principale può causare la sospensione dell'interfaccia utente e la mancata risposta ( documentazione ufficiale su ciò che accade).

Puoi rimediare mettendo queste attività più pesanti su un thread in background.

Un modo per farlo è usare AsyncTask , che fornisce un framework per facilitare l'uso di un thread in background e anche eseguire attività Thread UI prima, durante e dopo lo sfondo Thread ha completato il suo lavoro.

Metodi che possono essere sovrascritti durante l'estensione di AsyncTask :

  • onPreExecute() : richiamato sul thread UI prima onPreExecute()
  • doInBackground() : richiamato sul thread in background immediatamente dopo che onPreExecute() termina l'esecuzione.
  • onProgressUpdate() : richiamato sul thread dell'interfaccia utente dopo una chiamata a publishProgress(Progress...) .
  • onPostExecute() : richiamato sul thread dell'interfaccia utente al termine del calcolo dello sfondo

Esempio

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

}

Uso:

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

o semplicemente:

new MyCustomAsyncTask().execute(userSuppliedFilename);

Nota

Quando AsyncTask un AsyncTask possiamo passare tre tipi tra parentesi < > .
Definito come <Params, Progress, Result> (vedere la sezione Parametri )

Nell'esempio precedente abbiamo utilizzato i tipi <File, Void, String> :

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

Void viene utilizzato quando si desidera contrassegnare un tipo come non usato.

Si noti che non è possibile passare i tipi primitivi (cioè int , float e altri 6) come parametri. In questi casi, dovresti passare le loro classi wrapper , ad esempio Integer anziché int , o Float invece di float .

Il ciclo di vita AsyncTask e Activity

AsyncTasks non segue il ciclo di vita delle istanze di attività. Se si avvia un AsyncTask all'interno di un'attività e si ruota il dispositivo, l'attività verrà distrutta e verrà creata una nuova istanza. Ma AsyncTask non morirà. Continuerà a vivere fino al suo completamento.

Soluzione: AsyncTaskLoader

Una sottoclasse di Caricatori è AsyncTaskLoader. Questa classe svolge la stessa funzione dell'AsyncTask, ma molto meglio. Può gestire le modifiche alla configurazione delle attività più facilmente e si comporta nei cicli di vita di Fragments and Activities. La cosa bella è che AsyncTaskLoader può essere utilizzato in qualsiasi situazione in cui viene utilizzato AsyncTask. Ogni volta che i dati devono essere caricati in memoria per l'attività / frammento da gestire, AsyncTaskLoader può fare meglio il lavoro.

Annullare AsyncTask

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

Questo non ferma il tuo compito se fosse in corso, imposta semplicemente il flag cancellato che può essere controllato controllando il valore restituito da isCancelled() (assumendo che il tuo codice sia correntemente in esecuzione) facendo così:

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

Nota

Se un AsyncTask viene cancellato mentre doInBackground(Params... params) è ancora in esecuzione, allora il metodo onPostExecute(Result result) NON verrà chiamato dopo il doInBackground(Params... params) . AsyncTask richiamerà invece onCancelled(Result result) per indicare che l'attività è stata annullata durante l'esecuzione.

Pubblicazione dei progressi

A volte, abbiamo bisogno di aggiornare il progresso del calcolo fatto da un AsyncTask . Questo progresso potrebbe essere rappresentato da una stringa, un intero, ecc. Per fare ciò, dobbiamo usare due funzioni. Per prima cosa, dobbiamo impostare la funzione onProgressUpdate cui tipo di parametro è uguale al secondo parametro di tipo del nostro AsyncTask .

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

In secondo luogo, dobbiamo usare la funzione publishProgress necessariamente sulla funzione doInBackground , e questo è tutto, il metodo precedente farà tutto il lavoro.

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

Scarica immagine usando AsyncTask in Android

Questo tutorial spiega come scaricare l'immagine usando AsyncTask in Android. L'esempio seguente scarica l'immagine mentre mostri la barra di avanzamento durante il download.

Comprendere Android AsyncTask

L'attività asincrona consente di implementare MultiThreading senza sporcare le mani nei thread. AsyncTask consente l'uso corretto e semplice del thread dell'interfaccia utente. Permette di eseguire operazioni in background e di passare i risultati sul thread dell'interfaccia utente. Se stai facendo qualcosa di isolato relativo all'interfaccia utente, ad esempio il download di dati da presentare in un elenco, andare avanti e utilizzare AsyncTask.

  • AsyncTasks dovrebbe idealmente essere utilizzato per operazioni brevi (pochi secondi al massimo).
  • Un'attività asincrona è definita da 3 tipi generici, denominati Params, Progress e Result e 4 passaggi, chiamati onPreExecute() , doInBackground() , onProgressUpdate() e onPostExecute() .
  • In onPreExecute() è possibile definire il codice, che deve essere eseguito prima dell'inizio dell'elaborazione in background.
  • doInBackground ha un codice che deve essere eseguito in background, qui in doInBackground() possiamo inviare i risultati più volte al thread degli eventi con il metodo publishProgress (), per notificare che l'elaborazione in background è stata completata possiamo restituire risultati semplicemente.
  • onProgressUpdate() metodo onProgressUpdate() riceve gli aggiornamenti di avanzamento dal metodo doInBackground() , che viene pubblicato tramite il metodo publishProgress() e questo metodo può utilizzare questo aggiornamento di avanzamento per aggiornare il thread di eventi
  • onPostExecute() metodo onPostExecute() gestisce i risultati restituiti dal metodo doInBackground() .
  • I tipi generici usati sono
    • Params, il tipo di parametri inviati all'attività dopo l'esecuzione
    • Progresso, il tipo di unità di progresso pubblicate durante il calcolo dello sfondo.
    • Risultato, il tipo del risultato del calcolo dello sfondo.
  • Se un'attività asincrona non utilizza alcun tipo, può essere contrassegnata come tipo Void.
  • Un'attività asincrona in esecuzione può essere annullata chiamando il metodo cancel(boolean) .

Download di immagini tramite Android AsyncTask

il tuo layout .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 class

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

Dato che al momento non esiste un campo di commento per gli esempi (o non l'ho trovato o non ne ho il permesso) ecco alcuni commenti a riguardo:

Questo è un buon esempio di cosa si può fare con AsyncTask.

Tuttavia, l'esempio ha attualmente problemi con

  • possibili perdite di memoria
  • arresto anomalo dell'app se si verificava una rotazione dello schermo poco prima del completamento dell'attività asincrona.

Per dettagli vedi:

Passa Attività come Debolezza di Risanamento per evitare perdite di memoria

È normale che un AsyncTask richieda un riferimento all'attività che lo ha chiamato.

Se AsyncTask è una classe interna dell'attività, puoi fare riferimento direttamente a qualsiasi variabile / metodo membro.

Se, tuttavia, AsyncTask non è una classe interna dell'attività, sarà necessario passare un riferimento attività a AsyncTask. Quando si esegue questa operazione, un potenziale problema che potrebbe verificarsi è che AsyncTask manterrà il riferimento dell'attività fino a quando AsyncTask non avrà completato il proprio lavoro nel suo thread in background. Se l'attività è terminata o terminata prima che venga eseguito il lavoro sul thread in background di AsyncTask, AsyncTask avrà ancora il suo riferimento all'attività e, pertanto, non può essere sottoposto a Garbage Collection.

Di conseguenza, ciò causerà una perdita di memoria.

Per evitare che ciò accada, fai uso di un WeakReference in AsyncTask invece di avere un riferimento diretto all'Attività.

Ecco un esempio AsyncTask che utilizza un 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();
        }
    }
} 

Chiamare AsyncTask da un'attività:

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

Chiamando il AsyncTask da un frammento:

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

Ordine di esecuzione

Quando sono stati introdotti per la prima volta, AsyncTasks stato eseguito in serie su un singolo thread in background. A partire da DONUT , questo è stato modificato in un pool di thread che consente a più attività di operare in parallelo. A partire da HONEYCOMB , le attività vengono eseguite su un singolo thread per evitare errori di applicazione comuni causati dall'esecuzione parallela.

Se si desidera realmente l'esecuzione parallela, è possibile richiamare executeOnExecutor(java.util.concurrent.Executor, Object[]) con THREAD_POOL_EXECUTOR .

SERIAL_EXECUTOR -> Un Executor che esegue le attività una alla volta in ordine seriale.

THREAD_POOL_EXECUTOR -> Un Executor che può essere utilizzato per eseguire attività in parallelo.

campione :

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

AsyncTask: esecuzione seriale ed esecuzione parallela dell'attività

AsyncTask è una classe astratta e non eredita la classe Thread . Ha un metodo astratto doInBackground(Params... params) , che viene sovrascritto per eseguire l'operazione. Questo metodo è chiamato da AsyncTask.call() .

Executor fa parte del pacchetto java.util.concurrent .

Inoltre, AsyncTask contiene 2 Executor

THREAD_POOL_EXECUTOR

Utilizza i thread di lavoro per eseguire le attività parallelamente.

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

SERIAL_EXECUTOR

Esegue il compito in serie, cioè uno per uno.

private static class SerialExecutor implements Executor { }

Entrambi gli Executor sono statici , quindi THREAD_POOL_EXECUTOR solo un THREAD_POOL_EXECUTOR e un oggetto SerialExecutor , ma è possibile creare diversi oggetti AsyncTask .

Pertanto, se si tenta di eseguire più attività in background con l'Executor predefinito ( SerialExecutor ), queste attività saranno SerialExecutor ed eseguite in serie.

Se si tenta di eseguire più attività in background con THREAD_POOL_EXECUTOR , verranno eseguite parallelamente.

Esempio:

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

Esegui Fare clic sul pulsante più volte per avviare un'attività e vedere il risultato.

Attività eseguita nel pool di thread (1)

Ogni operazione richiede 1000 ms per essere completata.

A t = 36 s, le attività 2, 3 e 4 sono messe in coda e hanno iniziato l'esecuzione anche perché sono in esecuzione parallela.

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

Commento Task Executed in thread pool Task executed Serially Task Executed in thread pool (1) e uncomment Task executed Serially (2).

Esegui Fare clic sul pulsante più volte per avviare un'attività e vedere il risultato.

Sta eseguendo l'attività in modo seriale quindi ogni attività viene avviata dopo che l'attività corrente ha completato l'esecuzione. Di conseguenza, quando l'esecuzione del task 1 viene completata, solo l'attività 2 inizia a essere eseguita in background. Vice versa.

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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow