Programación Android, Service

Share if you like...Share on Facebook0Tweet about this on TwitterShare on Google+0Share on LinkedIn0

Un Service, o servicio, es un componente que realiza una tarea en background, sin que exista interfaz gráfica que interactúe con el usuario, y por lo tanto no tiene que cumplir con el ciclo de vida de las aplicaciones.

Generalmente un servicio se va a crear para realizar una actividad repetitiva, o que necesita realizar operaciones que necesitan bastante tiempo, como podría ser una descarga de un archivo, sincronizar datos de la apliación, etc.

Android ya nos ofrece el uso de diferentes servicios del sistema, a través de clases Manager específicas, a las que se accede a través del método getSystemService(String name), por ejemplo:

AlarmManager manager = (AlarmManager) getSystemService(String name);

Hay que tener en cuenta que los servicios, como cualquier otro objeto de la aplicación, corren sobre el proceso que lo ha creado (a menos que se indique lo contrario), y que no es un nuevo hilo. Esto quiere decir que si necesitamos que el servicio realice una acción con mucha carga de trabajo o que pueda bloquear el sistema, tendremos que crear un nuevo hilo dentro de nuestro servicio para realizar la tarea y evitar así los ANRs (Application Not Responding errors). Para más información consultar Processes and Threads.

Un servicio realiza dos tareas muy sencillas:

  • Una facilidad de la aplicación para indicar al sistema que se quiere realizar una tarea en background (incluso si el usuario no está interactuando con la aplicación). Esto se realiza con la llamada al método startService(Intent serv) de la clase Context, que hace la petición al sistema para realizar el servicio, hasta que el propio servicio se finalice a sí mismo, o el propio usuario lo pare explícitamente.
  • Una facilidad para cualquier aplicación para compartir alguna funcionalidad con otras aplicaciones. Esto se realiza llamando al método bindService(Intent serv, ServiceConnection conn, int flags), también de la clase Context, que permite realizar una conexión de larga duración con el propio servicio, para interactuar con él. Esto nos facilita, además, un interfaz cliente-servidor que permite a la interfaz gráfica realizar peticiones al servicio y obtener resultados. El servicio también debe finalizarse a sí mismo.
Ciclo de vida de un Service
Ciclo de vida de un Service

Crear un Service

En primer lugar, necesitamos crear una nueva clase que extienda de Service, que nos obligará a implementar el método onBind(Intent i), que de momento no vamos a tocar. Vamos a añadir también una variable String, que contendrá el nombre de nuestra clase, para posteriormente usar en el log:

public class MyService extends Service {
	private static final String TAG = "MyService";
	@Override
	public IBinder onBind(Intent i) {
		// TODO Auto-generated method stub
		return null;
	}
}

Y escribiremos también los métodos onStartCommand(Intent intent, int flags, int startId), donde ejecutaremos las tareas de nuestro servicio, y, para comprobar que se finaliza el método, onDestroy():

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
	Log.d(TAG, "FirstService started");
	// El servicio se finaliza a sí mismo cuando finaliza su trabajo.
	this.stopSelf();
	return super.onStartCommand(intent, flags, startId);
}

@Override
public void onDestroy() {
	// TODO Auto-generated method stub
	super.onDestroy();
	Log.d(TAG, "FirstService destroyed");
}

Con esto tendríamos nuestro servicio creado, el siguiente paso sería declarar el servicio en el manifest.xml, entre las etiquetas de inicio y fin de application (igual que si fuera una Activity), como ejemplo, si el package en el que se encuentra nuestra clase Service es com.proyectosimio.exampleservice.service, escribiremos:

<service android:name="com.proyectosimio.exampleservice.service.MyService" />

Para asignar proceso y memoria propios del servicio, además del atributo android:name, definiremos el atributo android:process, asignando los valores “remote” o “background”. Si además queremos que el servicio sea privado para la aplicación que lo declara, añadiremos dos puntos (:) delante del valor:

<service android:name="com.proyectosimio.exampleservice.service.MyService" android:process=":remote" />

Si lo que queremos es que accedan otras aplicaciones al servicio, utilizaremos los atributos android:exported y android:enabled asignando el valor “true”:

<service android:name="com.proyectosimio.exampleservice.service.MyService" android:exported="true" android:enabled="true" />

Iniciar el Service

Una vez declarado el servicio en el manifest.xml podremos lanzarlo desde nuestra Activity, en este caso por ejemplo lo lanzaremos desde el método onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);

	Intent servicio = new Intent(this, MyService.class);

	startService(servicio);
}

Con esto ya hemos lanzado nuestro servicio, y veremos en el LogCat del IDE los mensajes de comienzo y finalización del servicio. Sin embargo, si la tarea que tiene que realizar nuestro servicio pide una excesiva carga de trabajo, muy probablemente obtendremos el ANR que mencionamos antes, para comprobarlo haremos, en el método onStartCommand() de nuestro servicio, que el hilo realice una pausa de 15 segundos:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
	Log.d(TAG, "FirstService started");
	// El servicio se finaliza a sí mismo cuando finaliza su trabajo.
	try {
		Thread.sleep(100000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	this.stopSelf();
	return super.onStartCommand(intent, flags, startId);
}

Ahora, al lanzar nuestra apliacción, veremos que el dispositivo no responderá nada durante unos segundos, y finalmente el sistema nos avisará del ANR, para forzar cierre de aplicación o esperar. Para evitar que esto suceda lo que vamos a hacer es crear un nuevo Thread, o hilo, para que ejecute la tarea completa:

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

	Thread hilo = new Thread(new Runnable() {

		@Override
		public void run() {
			Log.d(TAG, "FirstService started");
			// El servicio se finaliza a sí mismo cuando finaliza su
			// trabajo.
			try {
				Thread.sleep(15000);
				Log.d(TAG, "sleep finished");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
	});

	hilo.start();

	this.stopSelf();
	return super.onStartCommand(intent, flags, startId);
}

Y en este caso, el dispositivo nunca se quedará colgado, y al ejecutar la aplicación veremos que en el LogCat del IDE aparecerán inmediatamente los avisos de creación y finalización del servicio, pero no aparecerá el mensaje de que ha terminado el bloqueo del hilo hasta pasados los 15 segundos, de manera que habremos conseguido ejecutar una tarea larga en segundo plano pero permitiendo al usuario seguir utilizando su dispositivo.

Otro dato a tener en cuenta es el valor que devuelve el método onStartCommand(). Este valor indica al sistema qué debe hacer cuando nuestro servicio sea matado, por ejemplo a causa de poca memoria. Los valores que podemos indicar son los siguientes:

  • Service.START_SICKY: El servicio se reinicia si se finaliza. Los datos que se pasan a través del Intent serán null. Se utiliza para servicios que manejan sus propios estados y no dependen de los datos del Intent.
  • Service.START_NOT_STICKY: El servicio no se reinicia. Se utiliza en servicios que se lanzan periódicamente. Sólo se reinicia si existen llamadas a startService() pendientes de ejecución.
  • Service.START_REDELIVER_INTENT: Es parecido a Service.START_STICKY, pero se relanza con el último Intent que llegó al método onStartCommand (con los datos que contenga).

Descargas

Puedes descargar el proyecto completo aquí.

Share if you like...Share on Facebook0Tweet about this on TwitterShare on Google+0Share on LinkedIn0
The following two tabs change content below.
Reborn as IT Developer. Desarrollador Android y fundador de Proyecto Simio. "En realidad, yo no puedo enseñar nada a nadie, sólo puedo hacerles pensar." - Sócrates.

One thought on “Programación Android, Service

Deja un comentario