Ver la Versión Completa : Crear Hilo de Carga de Datos
javichechu
15/09/15, 10:44:49
Buenos días.
Quería expresaros mi problema a ver si me pueden dar una solución o alguna pista.
En mi aplicación nativa Android, realizada con AndroidStudio, estoy haciendo un procedimiento de carga masiva al inicio de la aplicación, de manera que recibe vía SErvicio Web ciertos datos relevantes, y estos los guarda en la Base de Datos interna de la aplicación para evitar tener que llamar al SW nuevamente.
Esta tarea, la tengo pensada para que se ejecute al inicio, sale el clásico "Loading..." para que el usuario sepa que se está trabajando, y la intención es que tras finalizar, se vaya al Main de la App.
El problema es el siguiente. Como el thread pricipal, a su vez llama a métodos que por narices, tiene que ir en thread (Llamada a Servicio Web y Descarga de Imágenes) me está pasando que el thread principal termina antes de que los invocados dentro de él terminen, y por lo tanto, se va al Main antes de haber terminado de inertar datos en la BBDD y descargado las imágenes que también insertará en la BBDD.
Necesito lograr, que el proceso principal que regula toda esta carga inicial, quede en "Loading" hasta que los demás thread terminen.
¿cómo puedo lograr esto??? Mil gracias.
kriogeN
15/09/15, 12:36:19
Forma básica de Android:
Con un AsyncTask, el código que lanza a la segunda Activity una vez ha terminado de llamar al servicio web y descargar imágenes lo pones en el onPostExecute. Y el código que hace toda la descarga en el doInBackground.
Forma mejor:
Con la librería Volley de Google, en el Response.Listener pones el código que abre a la segunda Activity.
javichechu
15/09/15, 13:49:30
Hola.
Gracias por la contestación :dios:
Es precisamente un AsyncTask lo que utilizo para regular el proceso de carga masiva de datos. Dicho proceso, tiene en el doInBackground la creación de objeto de una clase que hace todas las operaciónes, y luego en el onPostExecute, hacemos la finalización del "Loading" y navegación hacia el Main de la app.
Etonces, y entrando en el Turrón, es el doInBackground de este AsyncTask principal, quien llama a un método que se encarga de hacer todo. Ese método hace dos cosas. Por un lado llama a los Servicios Web con otro AsyncTask, y en su onPostExecute rellenamos un array de objetos con esa información, y posteriormetne llama a otro AsyncTask, que cogiendo de esos objetos las rutas de unas imágenes lad descarga para finalmente tras la descarga, en su onPostExecute ya hace la insercción de datos e imágenes a la base de datos de la APP.
¿cómo me está funcionando? Pues el proceso principal, tras llamar al método que inicia la carga de todo desde su doInBackground, pasa por su onPostExecute y por ello se va al Main antes de que el resto de AsyncTask "hijas" terminen de trabajar, y por lo tanto, mientras la app sigue operando, por detrás está haciendo la carga de datos, descarga de imágenes y posterior insercción en BBDD, cuando lo que deseo, es que el loading se mantenga hasta que todo esto termine.
Siento que esto quede algo confuso, no se si me he explicado bien.
Gracias.
kriogeN
15/09/15, 13:56:34
Puedes anidar los AsyncTask, de tal forma que uno no empieza hasta que termine el otro.
O puedes poner 3 banderas (una en cada AsyncTask). Cada AsyncTask activa su bandera y comprueba si las otras 2 banderas están activadas. Si lo están pasa a la siguiente Activity, si no no hacen nada, ya lo hará el último AsyncTask que termine.
javichechu
15/09/15, 14:53:11
Puedes anidar los AsyncTask, de tal forma que uno no empieza hasta que termine el otro.
O puedes poner 3 banderas (una en cada AsyncTask). Cada AsyncTask activa su bandera y comprueba si las otras 2 banderas están activadas. Si lo están pasa a la siguiente Activity, si no no hacen nada, ya lo hará el último AsyncTask que termine.
Eso de las banderas me interesa...
¿Me puedes dar algo más de detalle o por Bandera te refieres a un booleano y listo?? Porque veo que los AsyncTask tienen una comprobación de su estado, si está running y demás, pero no consigo hacerlo con eso y algún sleep
:gracias:
kriogeN
15/09/15, 16:35:33
Eso de las banderas me interesa...
¿Me puedes dar algo más de detalle o por Bandera te refieres a un booleano y listo?? Porque veo que los AsyncTask tienen una comprobación de su estado, si está running y demás, pero no consigo hacerlo con eso y algún sleep
:gracias:
Por bandera me refiero a un booleano, si.
Imagina que tus procesos son solo 2, descargar los datos y descargar imágenes, y cada una lo haces en 2 AsyncTask distintos. Hasta que no terminen ambos no muestras la siguiente Activity.
Tienes un método llamado lanzarActivity() (por simplificar) y 2 Booleanos globales en tu Activity, uno llamado "terminaDatos" y el otro "terminaImagenes", ambos inicializados a false.
En el onPostExecute de la descarga de los datos haces:
terminaDatos = true;
if (terminaImagenes)
{
lanzarActivity();
}
Y en el onPostExecute() de la descarga de imágenes tienes el contrario:
terminaImagenes = true;
if (terminaDatos)
{
lanzarActivity();
}
Como los onPostExecute siempre se ejecutan en primer plano no hay problemas de concurrencia, hasta que no termine uno no empezará el otro. Con lo cual tu Activity sólo se lanzará 1 vez, aquella que termine la última.
NOTA: No pongo "terminaImagenes && terminaDatos" en los "if" (que es lo que de verdad debería lanzar la Activity) porque ya se establecen a true en su propio onPostExecute, con lo cual es un absurdo porque siempre son "true", pero si quieres ponerlo por claridad de código no está mal.
mocelet
15/09/15, 17:42:50
Las async task desde que cambiaron el executor por defecto en Android ¿4.0? a un sólo hilo no tienen mucha gracia para tareas en paralelo porque se encolan salvo que se indique lo contrario.
Así que lo más probable es que hasta que no termine una asynctask no ejecute la siguiente. Lo comento de cara a futuras optimizaciones, aunque lo suyo es usar alguna biblioteca tipo Volley como indicaba kriogeN.
kriogeN
15/09/15, 18:09:56
Las async task desde que cambiaron el executor por defecto en Android ¿4.0? a un sólo hilo no tienen mucha gracia para tareas en paralelo porque se encolan salvo que se indique lo contrario.
Así que lo más probable es que hasta que no termine una asynctask no ejecute la siguiente. Lo comento de cara a futuras optimizaciones, aunque lo suyo es usar alguna biblioteca tipo Volley como indicaba kriogeN.
Si, ya he dicho que era mejor forma, yo desde que descubrí Volley no uso otra cosa. Lo uso hasta para cachear imágenes y así también prescindo de Picasso y derivados.
Pero claro, adaptar una app entera para que use Volley es un trabajo, por eso he dicho que la más fácil era poner banderas en las AsyncTask.
javichechu
16/09/15, 16:23:43
Voy a mirar Volley también. Me parece interesante porque he visto aspectos importantes como evitar o corregir el parpadeo en la carga masiva de imágenes, ya que es algo que voy a utilizar mucho en la carga de Listados que tienen imágenes y he visto que Volley es potente también para eso.
Dexafree
16/09/15, 23:16:42
Aqui un fan acérrimo de Picasso (probé Glide pero no me terminó de gustar).
Para peticiones a API soy bastante fan de Ion, aunque tengo pendiente probar Retrofit.
Por si sirve, un compi del foro ( Arasthel ) creó AsyncJob para no tener que lidiar más con las AsyncTask para tareas sencillas: https://github.com/Arasthel/AsyncJobLibrary
El uso es super sencillo, sobretodo con los métodos estáticos.
Queda algo tal que
AsyncJob.doInBackground(new AsyncJob.OnBackgroundJob() {
override
public void doOnBackground() {
// Pretend it's doing some background processing
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Create a fake result (MUST be final)
final boolean result = true;
// Send the result to the UI thread and show it on a Toast
AsyncJob.doOnMainThread(new AsyncJob.OnMainThreadJob() {
override
public void doInUIThread() {
Toast.makeText(context, "Result was: "+ result, Toast.LENGTH_SHORT).show();
}
});
}
});
Y ya si usas retrolambda quedan métodos preciosos en los que puedes controlar de forma sencilla qué se hace en segundo plano y qué se hace en primer plano
javichechu
17/09/15, 09:11:30
Finalmente lo hice con banderas y funciona bastante bien.
El resumen es el siguiente.
1- Desde la Activity tengo un AsyncTask que controla la carga principal. Ese AsyncTask levanta la animación del "Cargando...".
2- Desde esa AsyncTask se crea un objeto para hacer todas las operaciones. En el constructor le paso la propia Activity. Invoco entonces al método de dicho objeto que hará la carga principal.
3- Dentro de ese método se hacen tres cosas. Cargar Cagegorías, cargar Subcategorías y cargar Características. Cada una de esas acciones, hace 3 AsyncTask. Una para invocar al WebServices y capturar los datos en Json. Otra para descargar imágenes de cierto campo que nos llega en ese json, y por último, otro para una vez tenemos los objetos montados, rellenando sus campos con los datos sacados del json y la imagen descargada, insertar la información en la Base de Datos de la APP.
4- Cada uno de esos procesos, en su onPostExecute llama a un método denominado ValidarFin, que lo que hace es comprobar si la bandera de cada uno de los tres procesos iniciados está levantada. En caso de estar levantadas todas, utilizando la Activity que recibe en el constructor, invoca al método "DotoMain" que ya hace un intent para ir al Main de la App y finalizar la carga.
5- A partir de esa carga inicial, que meto los datos en la BBDD, ya no tengo que hacer más llamadas al Servicio Web, dado que saco la información desde la BBDD de la APP, lo cual funciona bastante bien y ahorra llamadas a un Servicio Web. Cuantas más llamadas ahorre, mejor. No queremos extresarle... XD
Con esto, funciona perfectamente y la app queda en en la pantalla de Loading hasta que todos sus "subProcesos" terminen.
¿Aparte de usar volley, que iventisgaré con detenimiento... existe alguna recomendación más?
PD: Ya había visto Piccasso trasteqando por ahí. Me parece muy interesante. Como en ciertas partes, tengo galerías de imágenes a mostrar... le voy a pegar un buen vistazo a esta librería porque según he leído, merece muy mucho la pena.
vBulletin® v3.8.1, Copyright ©2000-2026, Jelsoft Enterprises Ltd.