Hay preguntas relacionadas, como ¿Cómo puedo pasar 2 parámetros a una clase AsyncTask? , pero me encontré con la dificultad de intentar en vano pasar múltiples primitivas como parámetros a una AsyncTask, así que quiero compartir lo que descubrí. Esta sutileza no se refleja en las preguntas y respuestas existentes, así que quiero ayudar a cualquiera que se encuentre con el mismo problema que yo y evitarle el dolor.
La pregunta es la siguiente: tengo varios parámetros primitivos (por ejemplo, dos longs) que quiero pasar a una AsyncTask para que se ejecute en segundo plano, ¿cómo se puede hacer? (Mi respuesta ... después de luchar con esto por un tiempo ... se puede encontrar a continuación).
android
android-asynctask
primitive
variadic-functions
robguinness
fuente
fuente
Respuestas:
Simplemente envuelva sus primitivas en un contenedor simple y páselo como un parámetro
AsyncTask
, así: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; ... } }
Llámalo así:
MyTaskParams params = new MyTaskParams(foo, bar, arple); MyTask myTask = new MyTask(); myTask.execute(params);
fuente
Otra forma: solo necesita agregar el constructor MyTask en su clase 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 }
Luego llame
new MyTask(int foo, long bar, double arple).execute();
Una segunda forma como la respuesta de David Wasser.
fuente
<(String,Object,int),Void,Void>
(Estrictamente hablando) NO es posible pasar múltiples primitivas a AsyncTask. Por ejemplo, si desea realizar
myTask.execute(long1, long2)
e intentar configurarprivate class myTask extends AsyncTask<long, Void, Void>
con el método correspondiente:@Override protected LocationItemizedOverlay doInBackground(long... params) {...}
su IDE probablemente se quejará de la necesidad de anular un método de supertipo. Tenga en cuenta que está utilizando la denominada firma del método Varargs para
doInBackground
, donde(long... params)
es como decir "Acepto un número variable de longs, almacenado como una matriz llamada params. No entiendo completamente qué causa que se presente una queja de compilador / IDE , pero creo que tiene que ver con cómoParams
se define la clase genérica .En cualquier caso, es posible lograr lo que desea sin ningún problema, siempre que envíe correctamente sus primitivas a sus respectivas envolturas no primitivas (por ejemplo, int => Integer, long => Long, etc.). En realidad, no es necesario convertir explícitamente sus primitivas en no primitivas. Java parece manejar eso por ti. Solo necesita configurar su ASyncTask de la siguiente manera (para el ejemplo 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] } ... }
Luego puede usar esta clase como lo pretendía originalmente, por ejemplo:
MyTask myTask = new MyTask(); myTask.execute(long1, long2);
O para cualquier número de primitivas que desee, SIEMPRE QUE SEAN DEL MISMO TIPO. Si necesita pasar varios tipos de primitivas, esto también se puede hacer, pero deberá modificar lo anterior para:
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]; } ... }
Esto es más flexible, pero requiere convertir explícitamente los parámetros a sus respectivos tipos. Si esta flexibilidad no es necesaria (es decir, un solo tipo de datos), recomiendo ceñirse a la primera opción, ya que es un poco más legible.
fuente
protected LocationItemizedOverlay doInBackground(Object[] objects)
y agregar lo siguiente para la definición de tarea asíncrona.private class MyTask extends AsyncTask<Object, Void, Void>
El método de ejecución integrado acepta una matriz de Params , pero todos deben ser del tipo definido ... así que si simplemente configuras el tipo de PARAM en OBJECT , puedes pasar lo que quieras siempre que sean hijos de objetos. ...
private class MyTask extends AsyncTask<Object, Void, Void> {
Luego, en su doInBackGround, simplemente lanza cada parámetro para volver a lo que necesita que sea:
@Override protected void doInBackground(Object... params) { Context t = (Context)params[0]; String a = (String) params[1]; List<LatLng> list = (List<LatLng>)params[2]; . . .
Y tu ejecución es simplemente:
new MyTask().execute(context,somestring,list_of_points);
No es tan buena como envolverlo en su propia clase contenedora, o un paquete, o hash o algo, porque depende del orden en ambos lados, pero funcionará. Por supuesto, podría convertir su matriz en un parámetro de HashMap (,) y básicamente está implementando un paquete personalizado en ese punto, pero funcionará.
fuente
Me gusta el método de malajisi, pero si no lo hiciste, ¿no podrías usar la clase Bundle?
Bundle myBundle = new Bundle(); myBundle.putInt("foo", foo); myBundle.putLong("bar", bar); myBundle.putDouble("arple", arple);
Luego, simplemente pase el paquete y descomprímalo dentro de MyTask. ¿Es esta una idea terrible? Evita crear una clase personalizada y es flexible si decide que necesita pasar parámetros adicionales más adelante.
Actualización: Han pasado bastantes años desde que escribí esta respuesta, y ahora realmente no me gusta. Recomendaría no usar un paquete. Si necesita pasar varios parámetros a un asynctask (o cualquier cosa, en realidad), use una clase personalizada que contenga todos sus parámetros a la vez. Usar un paquete es una buena solución a un problema que no debería tener. No existe ninguna ley que prohíba la creación de una clase personalizada para contener exactamente lo que necesita, y nada más.
Además, ¿por qué no estás usando corrutinas? Asynctasks son tan 2014.
fuente
Esto se resuelve mediante subclases. Google tiene un ejemplo para resolver este problema (subclases) en la documentación oficial de Android AsyncTask:
http://developer.android.com/reference/android/os/AsyncTask.html
Ejemplo:
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"); } }
fuente