84 votes

Comment passer plusieurs paramètres primitifs à une AsyncTask ?

D'autres questions connexes se posent, telles que Comment passer 2 paramètres à une classe AsyncTask ? mais je me suis heurté à la difficulté d'essayer en vain de passer plusieurs primitives en tant que paramètres à une AsyncTask, et je souhaite donc partager ce que j'ai découvert. Cette subtilité n'est pas prise en compte dans les questions et réponses existantes, et je veux donc aider ceux qui rencontrent le même problème que moi et leur épargner de la peine.

La question est la suivante : J'ai plusieurs primitif paramètres (par exemple deux longs) que je veux passer à une AsyncTask pour qu'elle soit exécutée en arrière-plan - comment cela peut-il être fait ? (Ma réponse... après avoir lutté avec cela pendant un certain temps... peut être trouvée ci-dessous).

158voto

David Wasser Points 23169

Il suffit d'envelopper vos primitives dans un simple conteneur et de le passer en paramètre à la fonction AsyncTask comme ceci :

private static class MyTaskParams {
    int foo;
    long bar;
    double arple;

    MyTaskParams(int foo, long bar, double arple) {
        this.foo = foo;
        this.bar = bar;
        this.arple = arple;
    }
}

private class MyTask extends AsyncTask<MyTaskParams, Void, Void> {
    @Override
    protected void doInBackground(MyTaskParams... params) {
        int foo = params[0].foo;
        long bar = params[0].bar;
        double arple = params[0].arple;
        ...
    }
}

Disons-le comme ça :

MyTaskParams params = new MyTaskParams(foo, bar, arple);
MyTask myTask = new MyTask();
myTask.execute(params);

99voto

malajisi Points 176

Autre façon de faire : Il suffit d'ajouter le constructeur MyTask dans la classe MyTask :

private class MyTask extends AsyncTask<String, Void, Void> {
    int foo;
    long bar;
    double arple;

    MyTask(int foo, long bar, double arple) { 
         // list all the parameters like in normal class define
        this.foo = foo;
        this.bar = bar;
        this.arple = arple;
    }
    ......   // Here is doInBackground etc. as you did before
}

Appelez ensuite

new MyTask(int foo, long bar, double arple).execute();

Une deuxième voie comme la réponse de David Wasser.

83voto

robguinness Points 2829

Il n'est (strictement) PAS possible de passer plusieurs primitives à AsyncTask. Par exemple, si vous voulez exécuter myTask.execute(long1, long2) et essayer de mettre en place private class myTask extends AsyncTask<long, Void, Void> avec la méthode correspondante :

@Override
protected LocationItemizedOverlay doInBackground(long... params) {...}

votre IDE se plaindra probablement de la nécessité de surcharger une méthode de type supérieur. Notez que vous utilisez la méthode dite Varargs pour la signature de la méthode doInBackground donde (long... params) revient à dire "J'accepte un nombre variable de longs, stockés dans un tableau appelé params. Je ne comprends pas complètement ce qui provoque une plainte du compilateur/IDE, mais je pense que c'est lié à la façon dont la classe générique Params est définie.

Dans tous les cas, il est possible d'obtenir ce que vous voulez sans problème, à condition de convertir correctement vos primitives en leurs enveloppes non primitives respectives (par exemple, int => Integer, long => Long, etc.). En fait, il n'est pas nécessaire de convertir explicitement les primitives en non primitives. Java semble gérer cela pour vous. Il vous suffit de configurer votre ASyncTask comme suit (pour l'exemple des longs) :

private class MyTask extends AsyncTask<Long, Void, Void> {

    @Override
    protected void doInBackground(Long... params) {
        // Do stuff with params, for example:
        long myFirstParam = params[0]
    }
    ...
}

Vous pouvez ensuite utiliser cette classe comme vous l'aviez prévu à l'origine, par exemple :

MyTask myTask = new MyTask();
myTask.execute(long1, long2);

Ou pour n'importe quel nombre de primitives que vous souhaitez, À CONDITION QU'ELLES SOIENT DU MÊME TYPE. Si vous avez besoin de passer plusieurs types de primitives, c'est également possible, mais vous devrez modifier ce qui précède :

private class MyTask extends AsyncTask<Object, Void, Void> {

    @Override
    protected void doInBackground(Object... params) {
        // Do stuff with params, for example:
        long myLongParam = (Long) params[0];
        int myIntParam = (Integer) params[1];

    }
    ...
}

C'est plus souple, mais cela nécessite de mouler explicitement les paramètres dans leurs types respectifs. Si cette flexibilité n'est pas nécessaire (c'est-à-dire un seul type de données), je recommande de s'en tenir à la première option, car elle est légèrement plus lisible.

9voto

user282172 Points 617

La méthode d'exécution intégrée accepte un tableau de Params mais ils doivent tous être du type défini ainsi, si vous définissez simplement l'élément PARAM type à OBJET vous pouvez alors passer ce que vous voulez tant qu'il s'agit d'enfants d'objets....

private class MyTask extends AsyncTask<Object, Void, Void> {

Ensuite, dans votre doInBackGround, il vous suffit de transformer chaque paramètre dans l'ordre en ce dont vous avez besoin :

 @Override
 protected void doInBackground(Object... params) {
     Context t = (Context)params[0];
     String a = (String) params[1];
     List<LatLng> list = (List<LatLng>)params[2];
     .
     .
     .

Et votre exécution est simple :

 new MyTask().execute(context,somestring,list_of_points);

Ce n'est pas aussi bien que de l'envelopper dans sa propre classe, ou dans un bundle, ou dans un hash ou autre, parce que vous dépendez de l'ordre des deux côtés, mais cela fonctionnera. Bien sûr, vous pourriez simplement faire de votre tableau un paramètre de HashMap(,) et vous seriez alors en train de personnaliser l'implémentation d'un bundle, mais cela fonctionnera.

7voto

MrPlow Points 61

J'aime bien la méthode de malajisi, mais si ce n'était pas le cas, ne pourriez-vous pas utiliser la classe Bundle ?

 Bundle myBundle = new Bundle();
 myBundle.putInt("foo", foo);
 myBundle.putLong("bar", bar);
 myBundle.putDouble("arple", arple);

Ensuite, il suffit de passer le paquet et de le décompresser dans MyTask. Est-ce une mauvaise idée ? Vous évitez de créer une classe personnalisée, et c'est flexible si vous décidez que vous avez besoin de passer des paramètres supplémentaires plus tard.

Mise à jour : Cela fait plusieurs années que j'ai écrit cette réponse, et je ne l'aime vraiment plus maintenant. Je vous déconseille d'utiliser un Bundle. Si vous avez besoin de passer plusieurs paramètres dans une asynctask (ou n'importe quoi d'autre, en fait), utilisez une classe personnalisée qui contient tous vos paramètres à la fois. L'utilisation d'un bundle est une bonne solution à un problème que vous ne devriez pas avoir. Il n'y a pas de loi contre la création d'une classe personnalisée pour contenir exactement ce dont vous avez besoin, et rien d'autre.

Par ailleurs, pourquoi n'utilisez-vous pas les coroutines ? Les asynctasks sont donc 2014.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X