«

»

oct 30 2012

Android Services (1/4)

Buenas a todos, en este tutorial aprenderemos a crear y consumir servicios/Services en Android. El tutorial está dividido en 4 partes. En éste primero explicaremos qué son los Services en Android, en el segundo post qué son y como se usan los BroadcastReceiver, el tercer post tratará sobre la creación de Services con uso de BroadcastReceiver y por último el cuarto será sobre la comunicación entre procesos con objetos tipo Messenger.

 

 

Usaremos Eclipse 4.2, Java 1.6 y Android 4.1, aunque como sabemos podemos usar otros entornos y “customizar” el uso de éstos para hacerlo. Así que si os interesa, ¡adelante, no dudéis en seguir leyendo!

 

¿Qué es un Service?

Un Service es un componente que trabaja en segundo plano y no es visible explícitamente al usuario. Los Services son el apoyo multitarea real para Android, ya que se puede ejecutar en su propio proceso. Si usamos hilos en las Activities, éstos estarán conectados al ciclo de vida de la Activity y el sistema Android podrá decidir poner fin en cualquier punto.

Android proporciona Services predefinidos, normalmente expuestos vía una clase específica Manager. El acceso a estos servicios se puede obtener a través del método getSystemService().
 

Declarar nuestro propio Service

Un Service debe ser declarado en AndroidManifest.xml a través de la siguiente sentencia :

 

<service android:name="yourclasss"> </service>

 

El nombre de la clase debe ser el de la clase que extienda de la clase Service o de una de sus subclases. Un Service no se ejecutará automáticamente en su propio hilo (thread), sin el atributo process el Service se ejecutará en el hilo principal de su proceso de acogida. Por lo que se deben realizar tareas de rendimiento intensivo en segundo plano.

 

Ejecutando un Service en su propio proceso

Podemos especificar que nuestro Service se ejecute en un proceso separado con el atributo process :

 

  android:process=":process_description"

 

De esta manera el Service obtiene su propio proceso y su propia memoria. Cualquier operación que requiera muchos datos en el servicio como por ejemplo, un recolector de basura, no afectará a la interfaz del usuario en el Activity. El prefijo dos puntos delante del nombre indica al sistema que el servicio es privado para la aplicación que lo declara. Si no usamos los dos puntos de prefijo, el Service sería un proceso global y podrá ser usado por otros componentes.

 

<service
    android:name="Servicio"
    android:process=":my_process"
    android:icon="@drawable/icon"
    android:label="@string/service_name">
</service>

 

La ejecución de un Service en su propio proceso no bloqueará la aplicación en caso de que el servicio haga largas operaciones en su hilo principal. Pero como los Services se ejecutan en su propio proceso, necesitamos usar algún proceso de comunicación (IPC) para comunicar el Service con otras partes.

 

Intent Services

Mientras que la clase base para crear Services es la clase Service, podemos también usar IntentService. IntentService es usado para desarrollar ciertas tareas en segundo plano. Una vez hecho, la instancia de IntentService acaba automáticamente. Un ejemplo de esto sería descargar algo de Internet. La clase IntentService nos ofrece el método onHandleIntent() que será llamado de forma asíncrona por el sistema.

 

Iniciando Services

Un Activity puede iniciar un Service desde el método startService() y parar el servicio desde el método stopService(). Si la Activity quiere interactuar con el Service puede usar el método de la clase Service bindService(). Para esto se requiere que el objeto ServiceConnection que permite conectar al Service y que devuelve un objeto IBinder. Este objeto IBinder puede ser usado por la Activity para comunicarse con el Service.

Una vez que el Service se inicia, se llama al método onCreate(). A continuación el método onStartCommand() es llamado con el dato Intent proporcionado por nuestra Activity. startService() también permite proporcionar un indicador o tag que determina el comportamiento del ciclo de vida de los servicios.

Service.START_STICKY se usa para los servicios que son explícitamente iniciados o parados. Los Services iniciados con el tag Service.START_NOT_STICKY finalizaran automáticamente después que el método onStartCommand() ha acabado.

Un Service es iniciado dentro del hilo principal de la aplicación por lo que todas las tareas de ejecución prolongada se deben realizar en segundo plano.

 

Comunicación con Services

Existen muchas maneras de comunicar una Activity con un Service y viceversa.

 

1. Comunicación a un servicio local

Si el Service es iniciado en el mismo proceso que la Activity, la Activity puede directamente comunicarse al servicio con la llamada al método bindService(). Este método tiene el parámetro ServiceConnection. El método onServiceConnected() es llamado en este objeto una vez que el servicio esté disponible. El Service devuelve en su método onBind() un objeto de tipo IBinder que puede ser usado para llamar al servicio.

A continuación un ejemplo de servicio local.
 

	public class LocalService extends Service{
		private NotificationManager mNM;
	
		//Número de identificación único para la Notificación
		//Lo usamos para iniciar y cancelar la Notificación
		private int NOTIFICATION = R.string.local_service_started;
		//Clase de acceso para los clientes. 
		//Como sabemos que este servicio siempre se ejecuta en el mismo proceso, no es necesario tratar con IPC
		public class LocalBinder extends Binder{	
			LocalService getService(){
				return LocalService.this;
			}
		}
		@Override
		public void onCreate(){
			mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);

			//Mostramos una notificación sobre el inicio. Ponemos un icono en la barra de estado.
			showNotification();	
		}
		@Override
		public int onStartCommand(Intent intent, int flags,int startId){
			Log.i("Local Service", "Received start id "+startId+": "+intent);
			//Queremos que el servicio continúe ejecutándose hasta que es explícitamente parado, así que devolvemos sticky
			return START_STICKY;	
		}
		@Override
		public void onDestroy(){
			//Cancelamos la notificación persistente
			mNM.cancel(NOTIFICATION);
			//Informamos al usuario que hemos parado
			Toast.makeText(this,R.string.local_service_stopped, Toast.LENGTH_SHORT).show();	
		}
		@Override
		public IBinder onBind(Intent intent){
			return mBinder;	
		}
	
		//Este es el objeto que recibe interacciones de los clientes. 
		private final IBinder mBinder = new LocalBinder();
	
		/*Mostramos la notificación mientras el servicio se está ejecutando*/
		private void showNotification(){
			CharSequence text = getText(R.string.local_service_started);
			//Ajustamos el icono, desplazamiento del texto y la hora y fecha
			Notification notification = new Notification(R.drawable.stat_sample, text, System.currentTimeMillis());
			//PendingIntent para lanzar nuestra actividad si el usuario selecciona esta notificación
			PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LocalServiceActivities.Controller.class), 0);
			//Ajustamos la información para mostrar en el panel de notificación
			notification.setLatestEventInfo(this, getText(R.string.local_service_label), text, contentIntent);
			//Enviamos la notificación
			mNM.notify(NOTIFICATION, notification);	
		}
	}	

 

2. Comunicación a un servicio en un proceso diferente

Para comunicar un Service que se ejecuta en un proceso diferente, necesitamos hacer uso de Inter Process Communication como los datos que necesitan ser enviados entre diferentes procesos. Para esto necesitamos crear un fichero AIDL que son aparentemente similares a interfaz en Java pero el fichero tiene extensión .aidl y sólo permite extender a otros ficheros AIDL.

Si las herramientas de desarrollo de Android lo encuentran en nuestro directorio, crearán automáticamente las clases stub necesarias para la comunicación IPC por nosotros.

 

3. Handler y Messenger

Si el servicio tuviese que comunicarse de nuevo con la Activity puede recibir un objeto de tipo Messenger desde el dato Intent que recibe de la Activity. Si el objeto tipo Messenger está ligado a un Handler en la Activity, el Service puede enviar objetos de tipo Message al Activity. Un Messenger es parcable, lo que significa que puede ser pasado a otros procesos y puede usarse este objeto para enviar Messages al Handler de la Activity. Messenger ofrece también el método getBinder() que permite pasar un Messenger a la Activity. La Activity a su vez, puede enviar Messages al Service.

 
Hasta aquí la primera parte de Services en Android. En el próximo post explicaremos qué son los BroadcastReceiver y su uso.
Un saludo!

 
Fuente | http://www.vogella.com

 

Espero que os haya gustado y si es así no lo dudéis y ¡¡compartid lo aprendido!!

 

Acerca del autor

InmaculadaAlcon

Me entusiasma aprender y desarrollar software de calidad. Crear aplicaciones para Android es lo que más me gusta y por lo que me muevo cada día. Soy muy flamenca, enamorada de Sevilla y con el sueño de trabajar algún día en Silicon Valley. Me encanta el fútbol y soy del Betis manque pierda.

  • caspol

    Hola ante todo, mis felicitaciones por los articulos que aparecen aqui, son muy muy interesantes, llevo algun tiempo siguiendo el blog pero es la primera vez que voy a comentar. Bueno mas que comentar, preguntar:

    - En un momento dado dices ” deben realizar tareas de rendimiento intensivo en segundo plano “, ¿para eso no estan los hilos?
    - A parte de que un Service se pueda ejecutar en otro proceso independiente y en su propia memoria, ¿que es lo que lo hace tan bueno con respecto a un hilo?

    Gracias y espero que sea el primero de muchos igual de buenos.

    • http://www.linkedin.com/in/inmaculadaalcon InmaculadaAlcon

      Hola, muchas gracias por seguirnos y espero que sigas leyéndonos. Te intentaré responder lo mejor que pueda a continuación:
      Los hilos, en Java o el lenguaje que sea, nos permiten realizar tareas en segundo plano, osea hacer varias cosas al mismo tiempo, pero si el programa tiene una interfaz gráfica de usuario y necesita hacer algo “pesado”, entonces usamos los hilos para evitar la congelación de la interfaz de usuario. Pero este hilo que usamos, acaba cuando termina el programa.
      Service, en cambio es una “especie de hilo” que funciona incluso cuando la aplicación no está en primer plano, es decir que si nos vamos a la pantalla principal del sistema y dejamos la aplicación, este Service en la aplicación seguirá funcionando.
      Un Service además sirve por si necesitamos mantener en funcionamiento algo mientras que el usuario pasa de una actividad a otra.
      Si necesitamos algo pesado en el Service, entonces usamos un hilo dedicado. Así nunca se congelará la interfaz. Así el Service actuará como punto de entrada, en donde podemos crear varios hilos si es necesario.
      En definitiva, un Service es una forma de decirle al sistema Android, que cierto código en nuestra aplicación es importante para el usuario y Android tiene que tener esto en cuenta para seguir funcionando incluso cuando no tenemos Activities activas. Por ejemplo las notificaciones.
      Espero que te haya aclarado a grandes rasgos qué diferencias hay :)
      Gracias por seguirnos. Si tienes alguna duda más o cualquier duda pues no dudes en escribirnos. Trataremos de contestarte en la medida que podamos.
      Un saludo! :)

  • http://www.twitter.com/javiferrer javiferer

    Felicidades Inma por el artículo.

    Tenía como uno de los temas pendientes profundizar sobre services y de un plumazo has resuelto muchas de mis dudas.

    Seguiré atento a tus posts!

    Gracias!

    • http://www.linkedin.com/in/inmaculadaalcon InmaculadaAlcon

      Gracias a ti por seguirnos :)
      Un saludo!

  • http://www.limecreativelabs.com Antonio

    Excelente! Los servicios son algo que conceptualmente tengo claro pero me cuesta mucho llevarlos a la práctica. Seguiré muy de cerca la serie de tutoriales a ver si despejo todas mis dudas.

    • http://www.linkedin.com/in/inmaculadaalcon InmaculadaAlcon

      Muchas gracias por seguirnos, espero que te sirva de ayuda y sin duda trataré de responderte lo más pronto posible a cualquier duda que te surja :)
      Un saludo!

  • http://www.none.com Toni M.L.

    Hola.

    antes de nada darte mi enhorabuena por el articulo. Muy esclarecedor en general: claro y conciso, como debe ser. Gracias.

    Soy bastante nuevo en el desarrollo de Android y no se muy bien como plantear una pequeña aplicacion: necesito una especie de proceso, que se inicie cuando se inicie el sistema que por una lado este constantemente escuchando del microfono y por otro lado exponga una especie de servicio REST que responda con datos de lo que esta escuchando por el microfono, es un sistema bastante sencillo, pero mi pregunta es: Supongo que la mejor manera de realizar esto es con un SERVICE de android no??? (Este programa no tiene interfaz de usuario) o hay por el contrario una alternativa mejor a los SERVICE??

    Gracias una vez mas, un saludo.

    • http://www.linkedin.com/in/inmaculadaalcon InmaculadaAlcon

      Hola, gracias a ti por seguirnos.
      Pues para tu situación en concreto yo usaría un BroadcastReceiver y a través del PendingIntent, con el intent que viene determinado por el sistema : Intent.ACTION_BOOT_COMPLETED , comprobarlo.
      En cualquier caso es que lo haría con esto. No conozco una manera mejor de hacerlo, aunque si encuentras, me gustaría que la compartieses.
      Sin interfaz de usuario, ¿qué realmente quieres hacer? jejeje Ya por curiosidad! :P

      P.D. De todas maneras investigaré y a ver si te puedo dar una pista mejor de cómo hacerlo :)

      Un saludo!

      • http://www.none.com Toni M.L.

        Hola Inmaculada!

        Muchas gracias por tu respuesta.

        Este servicio o app Android debe escuchar los latidos del corazón de un caballo por la entrada MIC o via USB (aun esta por decidir) y contar las pulsaciones por minuto. Por otro lado ese pequeño servicio web tipo REST o SOAP debe responder con el ultimo dato que te P.P.M del animal.

        Esto va montado en un cinturón alrededor del caballo en una placa tipo Raspberry conectada via Wifi.

        Un saludo y de nuevo muchas gracias por tu aclaraciones!

      • http://www.none.com Toni M.L.

        Ah, por supuesto que si encuentro una alternativa o simplemente algo interesante lo compartire con todos vosotros.

        Un saludo.

  • http://gravatar.com/gabrielpozo jackgris

    Muy bueno este post, como lectura complementaria a la docu oficial viene muy bien ;)

  • Alberto

    muchas gracias por el Post Inmaculada!!

    disculpa una duda, el servicio estará activo todo el tiempo? o solo mientras el activity principal siga activo?. (lo que pasa es que cuando cierro la app el servicio se para por completo jeje).

    de ser la segunda, habrá una manera de mantenerlo vivo todo el tiempo(o al menos hasta que se apague el dispositivo XD) despues de que se ejecuta la app por primera vez?

    de ser la primera… entonces algo me fallo por ahí jeje.

    de antemano muchísimas gracias.

    • http://www.linkedin.com/in/inmaculadaalcon InmaculadaAlcon

      Hola Alberto. No sé exactamente como lo has hecho. Pero a ver si te puede ayudar esto: http://developer.android.com/reference/android/app/Service.html#startForeground%28int,%20android.app.Notification%29

      Un saludo y muchas gracias. Y si se te presenta cualquier duda, por aquí estamos para ayudar :)

    • Saúl

      Hola alberto, no se si tenemos el miso problema. Cuando saco mi app de la lista de las últimas apps abiertas, se cierra el proceso de la app aunque se queda el servicio abierto, éste deja de funcionar. Solo me ha ocurrido con terminales nexus, con el resto de móviles que he probado al quitar la app aparece el proceso como reiniciando y se vuelve a activar sin problemas. No se si alguien sabe que puedo hacer para solucionar este problema.

  • http://www.facebook.com/tellezjavi Javier Tellez

    Para hacer un servicio que vaya comprobando un dato en una base de datos, por ejemplo cada segundo, como se haría?

  • Luis

    Hola muy buen post la verdad soy nuevo en esto de android pero estoy realmente sorprendido y quisera aprender un poco mas, Quisiera saber como puedo hacer que me nofique un cambio en la base datos en tiempo real.

  • http://poojava.site11.com/ Eduardo Díaz Salazar

    Hola:) Me gusto mucho este articulo! Pero tengo una duda.

    Estoy manejando el evento onKeyDown para que al presionar el botón físico de subir volumen durante 10 segundos realizar una acción en especifico, pero mi duda es ¿como lo hago con un servicio?…. Osea que no tenga que estar abierta la aplicación para que cuando se presiona el botón de subir volumen realizar alguna acción.

    Espero y puedas ayudarme con mi duda. Muchas Gracias:)

  • Ing Antovict González

    Buenos dias. A ver si me pueden ayudar. necesito realizar una apk que al recibir una llamada (Repique) me la cuelgue y seguido el cuelgue me llame a otro numero y lo cuelgue al tercer repique. como una especie de redirigir una llamada. lo que pasa es que al momento que me llaman debe verificar si tengo ese numero en mi DB para poder realizar la otra llamada. ya tengo adelantado que cuando me llamen llame seguido al otro numero pero me falta es colgar la llamada entrante automaticamente al repicar y la llamada de salida tambien colgarla al 3er repique. gracias de antemano