web-dev-qa-db-fra.com

Comment pouvez-vous passer plusieurs paramètres primitifs à AsyncTask?

Il y a des questions connexes, telles que Comment puis-je passer 2 paramètres à une classe AsyncTask? , mais j'ai eu la difficulté d'essayer en vain de passer plusieurs primitives en tant que paramètres à un AsyncTask, alors je veux partager ce que j'ai découvert. Cette subtilité n’est pas reflétée dans les questions et réponses existantes, je souhaite donc aider toutes les personnes qui rencontrent le même problème que moi et leur épargner la peine.

La question est la suivante: j’ai plusieurs paramètres primitifs (par exemple deux longs) que je souhaite transmettre à une AsyncTask à exécuter en arrière-plan - comment peut-il être fait? (Ma réponse ... après avoir lutté pendant un certain temps ... peut être trouvée ci-dessous.)

74
robguinness

Il est (strictement parlant) PAS possible de transmettre plusieurs primitives à AsyncTask. Par exemple, si vous voulez exécuter myTask.execute(long1, long2) et essayer de configurer 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 remplacer une méthode de type supertype. Notez que vous utilisez la signature Varargs , méthode de signature pour doInBackground, où (long... params) est comme dire "j’accepte un nombre variable de longs, stockés dans un tableau appelé params. Je ne comprends pas tout à fait la cause d’une plainte du compilateur/IDE, mais je pense que cela a à voir avec la façon dont la classe générique Params est défini.

Dans tous les cas, il est possible de réaliser ce que vous voulez sans problème, à condition que vous convertissiez correctement vos primitives dans leurs wrappers non primitifs respectifs (par exemple, int => Integer, long => Long, etc.). En fait, vous n'avez pas besoin de convertir explicitement vos primitives en non-primitives. Java semble gérer cela pour vous. Il vous suffit de configurer votre ASyncTask comme suit (pour l'exemple de 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 le vouliez initialement, par exemple:

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

Ou pour n'importe quel nombre de primitives que vous souhaitez, ils sont du même type. Si vous devez transmettre plusieurs types de primitives, vous pouvez également le faire, mais vous devrez modifier ce qui précède pour:

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 flexible, mais cela nécessite explicitement de convertir les paramètres en leurs types respectifs. Si cette flexibilité n’est pas nécessaire (c’est-à-dire un seul type de données), je vous recommande de vous en tenir à la première option, car elle est légèrement plus lisible.

77
robguinness

Emballez simplement vos primitives dans un simple conteneur et transmettez-les comme paramètre à 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;
        ...
    }
}

Appelez ça comme ça:

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

Une autre façon: il vous suffit d’ajouter le constructeur MyTask dans votre 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
}

Alors appelez

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

Une seconde façon, comme la réponse de David Wasser.

88
malajisi

La méthode execute intégrée accepte un tableau de Params, mais ils doivent tous être du type défini. Par conséquent, si vous définissez simplement le type PARAM sur OBJECT, vous pouvez alors transmettre ce que vous voulez, à condition qu'ils soient des enfants d'objets. ...

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

Ensuite, dans votre doInBackGround, il vous suffit de lancer chaque paramètre pour revenir à ce dont vous avez besoin:

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

Et votre exécution est simplement:

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

Pas aussi bonne forme que de l'envelopper dans votre propre classe wrapper, ou un paquet, ou un hachage ou quelque chose, parce que votre ordre dépend des deux côtés, mais cela fonctionnera. Bien sûr, vous pouvez simplement faire de votre tableau un paramètre de HashMap (,) et vous implémentez l’implémentation personnalisée d’un bundle à ce stade, mais cela fonctionnera.

6
Speckpgh

J'aime la méthode de malajisi, mais si vous ne l'aimiez pas, 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, passez simplement le paquet et décompressez-le dans MyTask. Est-ce une idée terrible? Vous évitez de créer une classe personnalisée et il est flexible si vous décidez de transmettre ultérieurement des paramètres supplémentaires.

6
MrPlow

Ceci est résolu via le sous-classement. Google a un exemple pour résoudre ce problème (sous-classement) dans la documentation officielle Android AsyncTask:

http://developer.Android.com/reference/Android/os/AsyncTask.html

Exemple:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    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));
                 // Escape early if cancel() is called
            if (isCancelled()) break;
        }
        return totalSize;
    }

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

    protected void onPostExecute(Long result) {
        showDialog("Downloaded " + result + " bytes");
    }
}
1
Bijan