¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Desarrolle una aplicación Android
  3. Tareas asíncronas y servicios
Extrait - Desarrolle una aplicación Android Programación en Java con Android Studio
Extractos del libro
Desarrolle una aplicación Android Programación en Java con Android Studio
2 opiniones
Volver a la página de compra del libro

Tareas asíncronas y servicios

Ejecutar acciones como tarea de fondo

En cualquier aplicación, el confort y la experiencia de usuario son aspectos esenciales: una aplicación debe, en smartphones y tabletas, reaccionar inmediatamente a cada solicitud del usuario. Para garantizar una respuesta óptima, la plataforma Android introduce una regla: de cualquier aplicación que no reaccione a una solicitud del usuario en un plazo de 10 segundos se dice que no responde. En tal situación, se produce un error ANR, de Application Not Responding («la aplicación no responde»), y el sistema puede detener la aplicación.

Para aquellas operaciones que pueden potencialmente tomar cierto tiempo (y cuya respuesta, por lo tanto, no es inmediata), se recomienda de forma especial realizar procesamientos asíncronos: la operación se ejecuta como tarea de fondo, y el usuario puede observar el progreso de la operación.

Si bien es posible implementar dicho mecanismo utilizando las tipicas clases de gestión de threads de Java, la plataforma provee una clase abstracta, android.os.AsyncTask, que se encarga de la mayor parte de la implementación de una solución asíncrona, aliviando el trabajo del desarrollador.


AsyncTask<Params, Progress, Result>
 

Los tipos genéricos Params, Progress, Result representan, como se detalla aquí arriba, los tipos de datos que se pasan como parámetro o devueltos por los métodos expuestos por la clase.

Para simplificar el diseño de una operación de tarea de fondo, AsyncTask separa el procesamiento en varias fases; cada una está representada por un método.

  • void onPreExecute(): este método se ejecuta cuando se lanza la tarea asíncrona. Se ejecuta en el thread principal, lo que permite manipular los componentes de la interfaz de usuario. No hay que invocar este método directamente, sino invocar el método execute, que lanza el procesamiento.

  • Result doInBackground(Params... params): este método es abstracto, debe sobrecargarse obligatoriamente, y se ejecuta en un thread como tarea de fondo cuando termina el método onPreExecute. En este método debe realizarse el procesamiento, y no permite llevar a cabo ninguna operación sobre los componentes de la interfaz. doInBackground recibe como parámetro un conjunto de datos de tipo genérico Params...

Desarrollar un servicio

Las tareas asíncronas permiten realizar operaciones como tarea de fondo, lo que deja al thread principal libre. Sin embargo, estas tareas asíncronas están vinculadas a una actividad; no pueden iniciarse de manera autónoma.

Esto puede plantear problemas en ciertos casos: por ejemplo, si la tarea que se debe realizar es larga, no podemos estar seguros a priori de que la actividad que ha creado la tarea asíncrona siga activa durante todo el procesamiento.

Para resolver este problema, Android ofrece la posibilidad de desarrollar servicios o bien componentes de aplicación desprovistos de interfaz de usuario.

Estos servicios deben basarse en la clase android.app.Service o en una de sus clases derivadas. Típicamente, en el marco de la ejecución de una tarea asíncrona larga, hay que utilizar la clase android.app.IntentService.

Esta clase es una especialización de android.app.Service, que integra todo el mecanismo de gestión de la tarea asíncrona: en efecto, por defecto, un servicio se ejecuta en el thread principal. IntentService se encarga de implementar la gestión de un thread como tarea de fondo y simplifica enormemente la implementación del servicio.

IntentService es una clase abstracta que hay que extender implementando el método onHandleIntent: este método se invoca directamente por el sistema cuando arranca el servicio. Su ejecución...

Comunicarse con un servicio

Si bien la comunicación entre una actividad y un servicio se realiza a través del objeto Intent que se pasa como parámetro, implementar una comunicación desde el servicio hacia la actividad que lo ha lanzado es un poco más complejo.

En primer lugar hay que definir un objeto de tipo Handler, que se encargue de la comunicación entre el servicio y la actividad. El objeto de tipo Handler debe implementar el método handleMessage:


private void startService() {  
   [...]   
   Handler handler = new android.os.Handler() {  
                        @Override  
                        public void handleMessage(Message msg) {  
                            [...]  
                        }  
                    };  
   [...]  
}
 

Este objeto Handler debe, a continuación, pasarse al servicio, en el Intent. Para ello se utiliza un objeto de tipo Messenger, que puede almacenarse en un Intent.


Messenger mensajero = new Messenger(handler);  
intent.putExtra("mensajero",mensajero);...

Utilizar los receptores de eventos

Además del mecanismo de mensaje/mensajero, existe otra solución, más general, que permite iniciar una comunicación entre un servicio y, por ejemplo, una actividad. Este mecanismo, los receptores de eventos, se utiliza con mucha frecuencia en el sistema Android.

Básicamente, un receptor de eventos es un componente de la aplicación cuyo rol es interceptar un evento y procesarlo.

Los eventos procesados pueden estar o bien generados por el sistema o bien por alguna aplicación. El capítulo Explotar el teléfono describe cómo procesar un evento generado por el sistema y el uso llamado estático de los receptores de eventos.

Aquí, en el marco de la comunicación con un servicio, los receptores de eventos permiten implementar una comunicación asíncrona con una actividad.

1. Definir un receptor de eventos

Un receptor de eventos es un objeto que hereda de la clase abstracta android.content.BroadcastReceiver. El método onReceive debe implementarse y se invoca tras la recepción del evento para el que se ha inscrito el receptor de eventos.


private BroadcastReceiver myBroadcastReceiver = new  
BroadcastReceiver() {  
  
        @Override  
        public void onReceive(Context context, Intent intent) {  
        }  
  
};
 

OnReceive recibe como parámetro el contexto de ejecución, así como un objeto de tipo Intent, que contiene la información transmitida....