Recherche…


Paramètres

Paramètre Détails
Params le type des paramètres envoyés à la tâche lors de l'exécution.
Le progrès le type des unités de progression publiées lors du calcul en arrière-plan
Résultat le type du résultat du calcul en arrière-plan.

Utilisation de base

Dans Activités et services Android, la plupart des rappels sont exécutés sur le thread principal . Cela simplifie la mise à jour de l'interface utilisateur, mais l'exécution de tâches lourdes sur le processeur ou l'E / S sur le thread principal peut entraîner une pause de votre interface utilisateur et une absence de réponse ( documentation officielle sur ce qui se passe alors).

Vous pouvez remédier à cela en plaçant ces tâches plus lourdes sur un thread d'arrière-plan.

Pour ce faire, vous pouvez utiliser une AsyncTask , qui fournit un cadre facilitant l'utilisation d'un thread en arrière-plan, et effectue également des tâches UI Thread avant, pendant et après la fin du thread Thread.

Méthodes pouvant être remplacées lors de l'extension d' AsyncTask :

  • onPreExecute() : invoqué sur le thread d'interface utilisateur avant l' exécution de la tâche
  • doInBackground() : invoqué sur le thread d'arrière-plan immédiatement après l' onPreExecute() de onPreExecute() .
  • onProgressUpdate() : invoqué sur le thread d'interface utilisateur après un appel à publishProgress(Progress...) .
  • onPostExecute() : invoqué sur le thread d'interface utilisateur une fois le calcul en arrière-plan terminé

Exemple

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

}

Usage:

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

ou simplement:

new MyCustomAsyncTask().execute(userSuppliedFilename);

Remarque

Lors de la définition d'une AsyncTask nous pouvons passer trois types entre < > .
Défini comme <Params, Progress, Result> (voir la section Paramètres )

Dans l'exemple précédent, nous avons utilisé les types <File, Void, String> :

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

Void est utilisé lorsque vous souhaitez marquer un type comme non utilisé.

Notez que vous ne pouvez pas passer de types primitifs (c.-à-d. int , float et 6 autres) en tant que paramètres. Dans de tels cas, vous devez passer leurs classes wrapper , par exemple Integer au lieu de int , ou Float au lieu de float .

Le cycle de vie AsyncTask et Activity

AsyncTasks ne suit pas le cycle de vie des instances d'activité. Si vous démarrez une tâche AsyncTask dans une activité et que vous faites pivoter le périphérique, l'activité sera détruite et une nouvelle instance sera créée. Mais la AsyncTask ne mourra pas. Il continuera à vivre jusqu'à la fin.

Solution: AsyncTaskLoader

Une sous-classe de chargeurs est AsyncTaskLoader. Cette classe remplit la même fonction que AsyncTask, mais beaucoup mieux. Il peut gérer plus facilement les modifications de la configuration d'activité et se comporte au cours des cycles de vie des fragments et des activités. La bonne chose est que AsyncTaskLoader peut être utilisé dans toutes les situations où AsyncTask est utilisé. Chaque fois que des données doivent être chargées en mémoire pour que l'activité / le fragment puisse être géré, AsyncTaskLoader peut mieux faire le travail.

Annuler AsyncTask

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

Cela n'arrête pas votre tâche si elle était en cours, elle définit simplement le drapeau annulé qui peut être vérifié en vérifiant la valeur de retour de isCancelled() (en supposant que votre code est en cours d'exécution) en procédant comme 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;
            }
        }
    }
}

Remarque

Si une AsyncTask est annulée alors que doInBackground(Params... params) est toujours en cours d'exécution, la méthode onPostExecute(Result result) ne sera PAS appelée après le doInBackground(Params... params) de doInBackground(Params... params) . AsyncTask appellera plutôt le onCancelled(Result result) pour indiquer que la tâche a été annulée pendant l'exécution.

Progrès de la publication

Parfois, nous devons mettre à jour la progression du calcul effectué par une AsyncTask . Cette progression peut être représentée par une chaîne, un entier, etc. Pour ce faire, nous devons utiliser deux fonctions. Tout d'abord, nous devons définir la fonction onProgressUpdate dont le type de paramètre est identique à celui du second paramètre de notre AsyncTask .

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

Deuxièmement, nous devons utiliser la fonction publishProgress nécessairement sur la fonction doInBackground , et c'est tout, la méthode précédente fera tout le travail.

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

Télécharger l'image en utilisant AsyncTask dans Android

Ce tutoriel explique comment télécharger Image en utilisant AsyncTask dans Android. L'exemple ci-dessous télécharge l'image tout en affichant la barre de progression pendant le téléchargement.

Comprendre Android AsyncTask

La tâche asynchrone vous permet d’implémenter MultiThreading sans que les mains soient sales dans les threads. AsyncTask permet une utilisation correcte et facile du thread de l'interface utilisateur. Il permet d'effectuer des opérations en arrière-plan et de transmettre les résultats sur le thread d'interface utilisateur. Si vous faites quelque chose d'isolement lié à l'interface utilisateur, par exemple en téléchargeant des données pour les présenter dans une liste, utilisez AsyncTask.

  • AsyncTasks devrait idéalement être utilisé pour des opérations courtes (quelques secondes au maximum).
  • Une tâche asynchrone est définie par 3 types génériques, appelés Params, Progress et Result, et 4 étapes, appelées onPreExecute() , doInBackground() , onProgressUpdate() et onPostExecute() .
  • Dans onPreExecute() vous pouvez définir du code, qui doit être exécuté avant le traitement en arrière-plan.
  • doInBackground a un code qui doit être exécuté en arrière-plan, ici dans doInBackground() nous pouvons envoyer des résultats à plusieurs fois au thread d'événement par la méthode publishProgress ().
  • onProgressUpdate() méthode onProgressUpdate() reçoit les mises à jour de progression de la méthode doInBackground() , publiée via la méthode publishProgress() . Cette méthode peut utiliser cette mise à jour pour mettre à jour le thread d'événement.
  • onPostExecute() méthode onPostExecute() gère les résultats renvoyés par la méthode doInBackground() .
  • Les types génériques utilisés sont
    • Params, le type des paramètres envoyés à la tâche lors de l'exécution
    • Progress, le type des unités de progression publiées lors du calcul en arrière-plan.
    • Résultat, le type du résultat du calcul en arrière-plan.
  • Si une tâche asynchrone n'utilise aucun type, elle peut alors être marquée comme type d'annulation.
  • Une tâche asynchrone en cours d'exécution peut être annulée en appelant la méthode cancel(boolean) .

Téléchargement d'image en utilisant Android AsyncTask

votre mise en page .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>

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

Comme il n'y a actuellement aucun champ de commentaire pour les exemples (ou que je ne l'ai pas trouvé ou que je n'ai pas l'autorisation de le faire), voici quelques commentaires à ce sujet:

C'est un bon exemple de ce que l'on peut faire avec AsyncTask.

Cependant, l'exemple a actuellement des problèmes avec

  • fuites de mémoire possibles
  • crash de l'application en cas de rotation de l'écran peu avant la fin de la tâche asynchrone.

Pour plus de détails voir:

Passer l'activité en tant que WeakReference pour éviter les fuites de mémoire

Il est courant qu'un AsyncTask exige une référence à l'activité qui l'a appelé.

Si AsyncTask est une classe interne de l'activité, vous pouvez la référencer directement, ainsi que toutes les variables / méthodes membres.

Si, cependant, AsyncTask n'est pas une classe interne de l'activité, vous devrez transmettre une référence d'activité à la tâche asynchrone. Lorsque vous cela effectuez, un problème potentiel qui peut se produire est que AsyncTask conservera la référence de l'activité jusqu'à ce que AsyncTask ait terminé son travail dans son thread d'arrière-plan. Si l'activité est terminée ou supprimée avant que le thread d'arrière-plan d'AsyncTask ne soit terminé, AsyncTask aura toujours sa référence à l'activité et ne pourra donc pas être collectée.

Cela entraînera une fuite de mémoire.

Pour éviter cela, utilisez une référence WeakRefer dans AsyncTask au lieu d'avoir une référence directe à l'activité.

Voici un exemple d'AsyncTask utilisant une référence WeakRefer:

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

Appel de la tâche asynchrone à partir d'une activité:

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

Appel de la tâche Async depuis un fragment:

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

Ordre d'exécution

Lors de la première introduction, AsyncTasks ont été exécutés en série sur un seul thread d'arrière-plan. À partir de DONUT , cela a été changé en un pool de threads permettant à plusieurs tâches de fonctionner en parallèle. À partir de HONEYCOMB , les tâches sont exécutées sur un seul thread pour éviter les erreurs d'application courantes provoquées par une exécution en parallèle.

Si vous voulez vraiment une exécution parallèle, vous pouvez appeler executeOnExecutor(java.util.concurrent.Executor, Object[]) avec THREAD_POOL_EXECUTOR .

SERIAL_EXECUTOR -> Un exécuteur exécutant les tâches une par une dans un ordre série.

THREAD_POOL_EXECUTOR -> Un exécuteur qui peut être utilisé pour exécuter des tâches en parallèle.

échantillon :

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

AsyncTask: exécution en série et exécution parallèle de la tâche

AsyncTask est une classe abstraite et n'hérite pas de la classe Thread . Il possède une méthode abstraite doInBackground(Params... params) , qui est remplacée pour effectuer la tâche. Cette méthode est appelée depuis AsyncTask.call() .

Les exécuteurs font partie du paquet java.util.concurrent .

De plus, AsyncTask contient 2 Executor s

THREAD_POOL_EXECUTOR

Il utilise des threads de travail pour exécuter les tâches en parallèle.

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

SERIAL_EXECUTOR

Il exécute la tâche en série, c'est-à-dire un par un.

private static class SerialExecutor implements Executor { }

Les deux Executor sont statiques , il existe donc un seul objet THREAD_POOL_EXECUTOR et un SerialExecutor objet SerialExecutor , mais vous pouvez créer plusieurs objets AsyncTask .

Par conséquent, si vous essayez d'effectuer plusieurs tâches en arrière-plan avec l'exécuteur par défaut ( SerialExecutor ), ces tâches seront mises en file d'attente et exécutées en série.

Si vous essayez d'effectuer plusieurs tâches en arrière-plan avec THREAD_POOL_EXECUTOR , elles seront exécutées en parallèle.

Exemple:

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

Effectuez un clic sur le bouton plusieurs fois pour démarrer une tâche et voir le résultat.

Tâche exécutée dans le pool de threads (1)

Chaque tâche dure 1000 ms.

À t = 36s, les tâches 2, 3 et 4 sont mises en file d'attente et ont commencé à s'exécuter également parce qu'elles s'exécutent en parallèle.

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

Commentaire Task Executed in thread pool (1) et décommenter Task executed Serially (2).

Effectuez un clic sur le bouton plusieurs fois pour démarrer une tâche et voir le résultat.

Il exécute la tâche en série, donc chaque tâche est démarrée après l'exécution de la tâche en cours. Par conséquent, lorsque l'exécution de la tâche 1 est terminée, seule la tâche 2 commence à s'exécuter en arrière-plan. 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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow