web-dev-qa-db-fra.com

Comment passer des variables dans et en dehors de AsyncTasks?

Je n'ai pas passé beaucoup de temps à travailler avec AsyncTasks sous Android. J'essaie de comprendre comment passer des variables de et vers la classe. La syntaxe:

class MyTask extends AsyncTask<String, Void, Bitmap>{

     // Your Async code will be here

}

c'est un peu déroutant avec la syntaxe < > à la fin de la définition de la classe. Jamais vu ce type de syntaxe auparavant. Il semble que je suis limité à ne passer qu'une valeur dans la variable AsyncTask. Est-ce que je me trompe en supposant cela? Si j'ai plus à passer, comment puis-je le faire?

En outre, comment est-ce que je retourne des valeurs de AsyncTask?  

C'est une classe et quand vous voulez l'utiliser, vous appelez new MyTask().execute() mais la méthode que vous utilisez dans la classe est doInBackground(). Alors, où retournez-vous réellement quelque chose?

15
Jake Wilson

Remarque: toutes les informations ci-dessous sont disponibles sur le Android Developers page de référence AsyncTask. L'en-tête Usage contient un exemple. Jetez également un coup d’oeil à la Threading indolore Android Entrée de blog de développeurs.

Jetez un oeil à le code source de AsynTask .


La notation amusante < > vous permet de personnaliser votre tâche async. Les crochets sont utilisés pour aider à mettre en œuvre les génériques en Java .

Vous pouvez personnaliser une tâche en 3 parties importantes:

  1. Le type des paramètres passés - n'importe quel nombre que vous voulez
  2. Le type de ce que vous utilisez pour mettre à jour la barre/indicateur de progression
  3. Le type de ce que vous retournez une fois terminé avec la tâche en arrière-plan

Et rappelez-vous que tout ce qui précède peut être une interface . Voici comment vous pouvez transmettre plusieurs types lors d’un même appel!

Vous placez les types de ces 3 choses entre les chevrons:

<Params, Progress, Result>

Donc, si vous allez passer URLs et utiliser Integers pour mettre à jour la progression et renvoyer un booléen indiquant le succès, vous écrirez:

public MyClass extends AsyncTask<URL, Integer, Boolean> {

Dans ce cas, si vous téléchargez des bitmaps par exemple, vous manipulerez ce que vous ferez avec les bitmaps en arrière-plan. Vous pouvez également simplement renvoyer une HashMap de Bitmaps si vous le souhaitez. Rappelez-vous également que les variables de membre que vous utilisez ne sont pas restreintes. Par conséquent, ne vous sentez pas trop attaché par les paramètres, les progrès et les résultats.

Pour lancer une AsyncTask, instanciez-la, puis execute -le de manière séquentielle ou parallèle. Lors de l'exécution, vous passez vos variables. Vous pouvez en passer plus d'un.

Notez que vous n'appelez pas directement doInBackground(). En effet, cela casserait la magie de la tâche Async, à savoir que doInBackground() est créé dans un thread en arrière-plan. L'appeler directement tel quel le ferait tourner dans le thread d'interface utilisateur. Donc, vous devriez plutôt utiliser une forme de execute(). Le travail de execute() consiste à lancer le doInBackground() dans un thread en arrière-plan et non dans le thread UI.

Travailler avec notre exemple d'en haut.

...
myBgTask = new MyClass();
myBgTask.execute(url1, url2, url3, url4);
...

onPostExecute se déclenche lorsque toutes les tâches de l'exécution sont terminées.

myBgTask1 = new MyClass().execute(url1, url2);
myBgTask2 = new MyClass().execute(urlThis, urlThat);

Remarquez comment vous pouvez transmettre plusieurs paramètres à execute(), qui les transfère à doInBackground(). C’est par l’utilisation de varargs (vous savez comme String.format(...). Plusieurs exemples ne montrent que l’extraction de la premiers paramètres en utilisant params[0], mais vous devriez assurez-vous de bien avoir tous les paramètres. Si vous passez dans les URL, cela serait (tiré de l'exemple AsynTask, il y a plusieurs façons de le faire):

 // This method is not called directly. 
 // It is fired through the use of execute()
 // It returns the third type in the brackets <...>
 // and it is passed the first type in the brackets <...>
 // and it can use the second type in the brackets <...> to track progress
 protected Long doInBackground(URL... urls) 
 {
         int count = urls.length;
         long totalSize = 0;

         // This will download stuff from each URL passed in
         for (int i = 0; i < count; i++) 
         {
             totalSize += Downloader.downloadFile(urls[i]);
             publishProgress((int) ((i / (float) count) * 100));
         }

         // This will return once when all the URLs for this AsyncTask instance
         // have been downloaded
         return totalSize;
 }

Si vous envisagez de réaliser plusieurs tâches de groupe, vous devez considérer que les appels myBgTask1 et myBgTask2 ci-dessus sont effectués en séquence . C’est génial si un appel dépend de l’autre, mais si les appels sont indépendants - par exemple, vous téléchargez plusieurs images et vous ne vous souciez pas des images qui arrivent en premier - vous pouvez alors faire le myBgTask1 et myBgTask2 appelle en parallèle avec le THREAD_POOL_EXECUTOR:

myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2);
myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat);

Remarque:

Exemple

Voici un exemple AsyncTask pouvant prendre autant de types que vous le souhaitez sur la même commande execute(). La restriction est que chaque type doit implémenter la même interface:

public class BackgroundTask extends AsyncTask<BackgroundTodo, Void, Void>
{
    public static interface BackgroundTodo
    {
        public void run();
    }

    @Override
    protected Void doInBackground(BackgroundTodo... todos)
    {
        for (BackgroundTodo backgroundTodo : todos)
        {
            backgroundTodo.run();

            // This logging is just for fun, to see that they really are different types
            Log.d("BG_TASKS", "Bg task done on type: " + backgroundTodo.getClass().toString());
        }
        return null;
    }
}

Maintenant vous pouvez faire:

new BackgroundTask().execute(this1, that1, other1); 

Où chacun de ces objets est d'un type différent! (qui implémente la même interface)

45
Peter Ajtai

Je reconnais que c'est une réponse tardive, mais voici ce que je fais depuis un moment. 

Lorsque j'ai besoin de transmettre une série de données à une AsyncTask, je peux soit créer ma propre classe, la transmettre et accéder à ses propriétés, comme ceci:

public class MyAsyncTask extends AsyncTask<MyClass, Void, Boolean> {

    @Override
    protected Boolean doInBackground(MyClass... params) {

        // Do blah blah with param1 and param2
        MyClass myClass = params[0];

        String param1 = myClass.getParam1();
        String param2 = myClass.getParam2();

        return null;
    }
}

puis y accéder comme ceci:

AsyncTask asyncTask = new MyAsyncTask().execute(new MyClass());

ou je peux ajouter un constructeur à ma classe AsyncTask, comme ceci:

public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {

    private String param1;
    private String param2;

    public MyAsyncTask(String param1, String param2) {
        this.param1 = param1;
        this.param2 = param2;
    }

    @Override
    protected Boolean doInBackground(Void... params) {

        // Do blah blah with param1 and param2

        return null;
    }
}

puis y accéder comme ceci:

AsyncTask asyncTask = new MyAsyncTask("String1", "String2").execute();

J'espère que cela t'aides!

9
LukeWaggoner

Etant donné que vous pouvez passer un tableau d'objets entre crochets, c'est le meilleur moyen de transmettre des données en fonction du traitement que vous souhaitez effectuer en arrière-plan.

Vous pouvez transmettre la référence de votre activité ou la vue dans le constructeur et l'utiliser pour transmettre des données à votre activité.

class DownloadFilesTask extends AsyncTask<URL, Integer, List> {
    private static final String TAG = null;
    private MainActivity mActivity;
    public DownloadFilesTask(MainActivity activity) {
        mActivity = activity;
        mActivity.setProgressBarIndeterminateVisibility(true);
    }

    protected List doInBackground(URL... url) {
        List output = Downloader.downloadFile(url[0]);
        return output;
    }

    protected void onProgressUpdate(Integer... progress) {
        setProgressPercent(progress[0]);
    }

    private void setProgressPercent(final Integer integer) {
        mActivity.setProgress(100*integer);
    }

    protected void onPostExecute(List output) {

        mActivity.mDetailsFragment.setDataList((ArrayList<Item>) output);

        //you could do other processing here
    }
}
2
Rajdeep Dua

Passer une chaîne simple:

 public static void someMethod{ 
     String [] variableString= {"hello"};
     new MyTask().execute(variableString);
}

static class MyTask extends AsyncTask<String, Integer, String> {

        // This is run in a background thread
        @Override
        protected String doInBackground(String... params) {
            // get the string from params, which is an array
            final String variableString = params[0];

            Log.e("BACKGROUND", "authtoken: " + variableString);

            return null;
        }
    }
0
Afshin Ghazi

Alternativement, vous pouvez simplement utiliser un thread standard et un gestionnaire d’usage pour renvoyer des données au thread ui en redéfinissant la fonction handlemessage.

0
Kevin