5

Tengo varias subclases de actividad en mi proyecto, cada una de las cuales llama a un servicio web basado en SOAP, procesa y muestra los resultados. La serialización SOAP, el manejo de llamadas y el análisis del resultado en varios objetos POJO se encapsulan en la clase MyWebService. Esta clase ejecuta la (s) llamada (s) de servicio web real a través de una AsyncTask.¿Patrón para reutilizar Android AsnycTask en varias actividades?

Para poder devolver los resultados a la subclase de actividad de llamada, calculé que todas estas actividades deberían implementar una interfaz WebServiceResultProcessor, que define una única función (processWebServiceResults) que actúa como una devolución de llamada para AsyncTask, llamada desde onPostExecute .

También quiero mostrar un ProgressDialog durante la llamada al servicio web. Y aquí viene mi pregunta. Para poder mostrar el ProgressDialog (ya sea desde MyWebService o AsyncTask), necesito pasar una referencia al Contexto de la actividad de la persona que llama. Y para poder ejecutar la función de devolución de llamada desde AsyncTask, I también necesita pasar la misma referencia de objeto, pero esta vez como WebServiceResultProcessor. Esto me parece un olor a código, pasando el mismo objeto dos veces, pero no veo ninguna forma de evitarlo. En lugar de interactuar, podría crear una nueva clase base, extender la clase Activity e imponer la herencia de la clase de extensión, pero eso significaría que excluiría ListActivity y los gustos de usar esta clase MyWebService.

¿Hay una mejor manera de hacerlo?

+0

¿Su WebServiceResultProcessor extienden Contexto/actividad? –

+0

@HeikoRupp no, y probablemente preferiría mantenerlo así. –

Respuesta

0

A pesar de la advertencia de Arhimed, terminé usando AsyncTask, ya que todavía se ajusta a mis propósitos. Solo me aseguro de que todas las actividades que llaman a servicios web, en su onDestroy(), envíen un cancel() a la AsyncTask invocada. La implementación AsyncTask maneja con gracia la solicitud de cancelación marcando isCancelled() en todas partes donde sea necesario.

En cuanto a la pregunta original, debo haber tenido un error: la solución es realmente simple.Paso la instancia de la subclase Activity como un Objeto a la AsyncTask, y la echo a Context o WebServiceResultProcessor, según sea necesario. Los fragmentos que muestra cómo funciona:

if (callerActivity instanceof Context) { 
    ProgressDialog dialog = new ProgressDialog((Context)callerActivity); 
} 

...

if (callerActivity instanceof WebServiceResultProcessor) { 
    ((WebServiceResultProcessor)callerActivity).processWebServiceResults(soapObject); 
} 
+1

Creo 'if (instancia de llamador instanceof Context) {..}' es una verificación redundante. A menos que me falta algo, 'callerActivity' en su caso siempre será una instancia de' Context', por lo que puede llamar directamente al código de creación de progreso. –

4

+1, una buena pregunta!

Esta no es una respuesta directa a su pregunta. Sin embargo, déjame decirte que creo que AsyncTask no es una buena opción para esas cosas. Creo que sí porque en este caso AsyncTask contiene una referencia a una instancia de Activity (a través de ProgressDialog o de las devoluciones de llamadas desde onPostExecute()).

Imagínese: en Android el sistema operativo puede matar al Activity antes de AsyncTask ejecuta su doInBackground(). Esto es, por supuesto, una especie de caso de esquina, pero no es imposible. Considere un escenario: el usuario recibe una llamada entrante, su actividad se vuelve invisible, el sistema operativo necesita algo más de RAM y, por lo tanto, decide matar su actividad. Un caso de fuga de memoria, al menos.

No sé por qué Google literalmente oculta la información sobre cómo la UI debe separarse adecuadamente de las tareas en segundo plano. Sí, dicen "usar un servicio". Pero no es una tarea trivial. Es una lástima que Google brinde buenas guías para casi todos los temas de desarrollo, pero no en este. Sin embargo, puedo sugerir que verifique la presentación "Google I/O 2010 - Android REST client applications" como inspiración. Parece que dieron una clave sobre cómo deberían hacerse esas cosas en Android.

+0

gracias por señalar los peligros utilizando la referencia de contexto desde AsyncTask. Encontré este http://stackoverflow.com/questions/3357477/is-asynctask-really-conceptually-flawed-or-am-i-just-missing-something pregunta y respuestas para cubrir este tema bastante extensamente. –

+0

@ András Szepesházi: gracias, es una buena discusión. Sin embargo, en su mayoría discuten cómo realizar cambios en la configuración (por ejemplo, la actividad se reinicia en la rotación del dispositivo). Pero, ¿qué sucede si la actividad se cancela dentro del escenario descrito por mí (llamada entrante) mientras hay una asynctask que crea una nueva cuenta de usuario en el servidor remoto? :) Se creará una cuenta, pero cuando el usuario vuelva a la actividad, nunca sabrá el resultado de la asynctask. ¿Entonces el usuario volverá a intentar y obtendrá el error "Ese nombre de usuario ya está en uso"? :) Ok, ¿y si asycntask hizo una transacción de pago? :) –

+0

wow esto es malo. Quería evitar el uso de Servicios y Manejadores, pero parece que este es el único camino a seguir. –

3

Puede echarle un vistazo a este artículo de blog (part 1 y part 2), que implementa un servicio web con AsyncTaskLoader y el mismo servicio web con un componente de servicio. Además, muestra las diferencias entre ambos enfoques y también hay comentarios interesantes para el artículo.

Cuestiones relacionadas