Bienvenidos sean a este post, hoy hablaremos sobre los servicios en Android los cuales existen para cuando necesitamos un nuevo elemento en nuestra aplicacion que se ejecute en segundo plano sin necesidad de tener una interaccion por parte del usuario, estos tienen una doble funcion:

Anuncios
  • La primera funcion permite indicarle al sistema que el nuevo elemento ha de ejecutarse en segundo plano, en general durante un largo periodo de tiempo. Estos se inician por medio de startService() que se ejecuta de forma infinita hasta que se indique lo contrario.
  • Los servicios a su vez permiten que nuestra aplicacion se comunique con otras aplicaciones, estos se inician por medio de bindService(), el cual permite establecer una conexion con el servicio e invocar alguno de los metodos que se ofrecen

Cuando se crea un servicio con alguno de los metodos anteriores, el sistema instancia al mismo y llama al metodo onCreate(), la labor del servicio es implementar un comportamiento adecuado, en general la tarea es crear un hilo secundario (thread) para correr nuestra tarea. Como hemos visto anteriormente, los servicios al igual que los elementos de una aplicacion se ejecutan por el hilo principal de la aplicacion, ocasionando que en caso de necesitar un uso intensivo del CPU se produzca el bloqueo de nuestra aplicacion u otras acciones, para evitar esto se puede utilizar un hilo secundario creado por medio de IntentService().

Nuestro siguiente paso seran los ciclos de vida de un servicio, como dijimos antes existen dos formas de llamar a un servicio, si lo hicieramos por medio de startService(), el sistema comenzara creando un hilo y llamando a onCreate(), despues iniciara a onStartCommand(), el cual veremos mas adelante, y este continuara hasta que se llame a stopService() o stopSelf(). Cuando iniciamos un servicio en segundo plano podemos correr el riesgo de que este sea eliminado por escasez de memoria, como hemos hablado cuando vimos ciclos de vida, para evitar esto podemos configurar al sistema para que reaccione dependiendo de un valor informado por medio de onStartCommand(). Los valores que podemos utilizar son:

  • START_STICKY, es utilizado para indiciar al sistema que intente crear de nuevo el proceso cuando disponga de memoria suficiente
  • START_NOT_STICKY, indicara que el servicio sera creado solamente si envia una nueva solicitud de creacion

Recordando cuando hablamos de los ciclos de vida de una actividad, ante la eventualidad de poca memoria un servicio sera menos prioritario que una actividad en primer plano pero mas importante que otras aplicaciones en segundo plano, es decir que un servicio solo sera eliminado en caso de alta necesidad pero si la aplicacion visible esta conectado al servicio este tambien es considerado como visible siendo tan importante como la aplicacion en primer plano.

Anuncios

Otra funcion para utilizarlo es por medio de bindService(), esta nos permitira una conexion persistente de un servicio. La diferencia esta en si el servicio no esta en ejecucion, sera creado por medio de onCreate() pero no se llamara a onStartCommand(), en su lugar se llamara a onBind() que devolvera a un objeto IBinder el cual se encargara de la comunicacion entre el cliente y el servicio, esta comunicacion sera establecidad por medio una interfaz escrita en AIDL (Android Interface Definition Language), este se encarga del intercambio de objetos entre aplicaciones que corren en procesos separados. La permanencia del servicio estara definida por el tiempo en que la conexion este establecida, independiente de que se mantenga la referencia o no al objeto IBinder. Otra opcion es diseñar un servicio que se puede iniciar con ambos metodos, esto producira un servicio que permanecera activo si ha sido creado desde a aplicacion que lo contiene o si recibe conexiones desde otras aplicaciones.

Nota: En bindService() se puede hacer siempre y cuando tengamos activado el flag BIND_AUTO_CREATE.

Tambien podemos conceder permisos, para ellos podemos conceder a un acceso global por medio de la etiqueta service, tambien podemos restringir su acceso, esto por medio de uses-permission, el permiso definido puede ser para iniciar, detener o conectarse. Como adicional podemos restringir el acceso a algunas funciones especificas de un servicio.

Nota: Recuerden siempre que los permisos son en el archivo de Manifiesto (AndroidManifest.xml)

Pasemos a crear un ejemplo para ver el funcionamiento de ejecucion en segundo plano, vamos a Android Studio y generemos un proyecto con las siguientes caracteristicas:

  • Application Name: Servicio Música
  • Domain company: example.org
  • SDK Minimum (Phone and Tablet): 14
  • Add an Activity: Empty Activity

Una vez creado nuestro proyecto modifiquemos el archivo activity_main.xml por el siguiente codigo:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Servicio de reproduccion de música" />
    <Button
        android:id="@+id/boton_arrancar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Arrancar Servicio" />
    <Button
        android:id="@+id/boton_detener"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Detener Servicio" />
</LinearLayout>

Este es un layout sencillo donde tendremos un texto y dos botones para iniciar y detener el servicio. Nuestro siguiente paso sera agregar el recurso de musica para reproducir, primero crearemos el directorio de recurso donde lo contendremos, para eso deben hacer click con el boton derecho sobre la carpeta res y seleccionar New -> Android Resource Directory, luego en Directory Name ingresen raw y en Resource Type seleccionen raw, el resto debe quedar como esta, pulsen Ok para generar el nuevo recurso, con nuestro recurso en el contenedor res ahora tienen dos opciones: Pueden tomar un archivo en formato MP3 de ustedes y renombrarlo a audio.mp3 o descargar el siguiente archivo:

Anuncios

Una vez renombrado o descargado el archivo, deben copiarlo desde la carpeta donde este ubicado por medio de Ctrl+C o click con el boton derecho y la opcion Copiar, despues van al nuevo recurso que creamos y hacen Ctrl+V o click con el boton derecho para pegarlo, despues de hecha esta accion aparecera un cuadro para renombrarlo pero deben dejarlo como audio.mp3 y en la carpeta de destino informada, no deben modificarla, pulsen Ok para copiarla, una vez realizada aparecera como un nuevo recurso.

Nota: En la mayoria de los casos una vez hecho esto puedan necesitar sincronizar nuevamente el proyecto para ello vayan a File -> Sync project with Gradle Files para reconocer el nuevo recurso.

Despues de modificado nuestro layout y copiado nuestro archivo de musica, procedamos a crear una nueva clase de Java llamada ServicioMusica, para ello deben ir al contenedor de las clases Java, click con el boton derecho y selecionen New -> Java class, en Name usen ServicioMusica, dejen el resto como aparece y pulsen Ok para crear la clase, una vez generada modificaremos el codigo generado por el siguiente:

package org.example.serviciosmsica;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
import android.widget.Toast;

public class ServicioMusica extends Service {
    MediaPlayer reproductor;

    @Override
    public void onCreate(){
        Toast.makeText(this,"Servicio creado",
                Toast.LENGTH_SHORT).show();
        reproductor = MediaPlayer.create(this,R.raw.audio);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int idArranque){
        Toast.makeText(this,"Servicio iniciado",
                Toast.LENGTH_SHORT).show();
        reproductor.start();
        return START_STICKY;
    }

    @Override
    public void onDestroy(){
        Toast.makeText(this,"Servicio Detenido",
                Toast.LENGTH_SHORT).show();
        reproductor.stop();
    }

    @Override
    public IBinder onBind(Intent intencion){
        return null;
    }
}

En esta clase extenderemos Service, crearemos un objeto de MediaPlayer llamado reproductor, luego en el metodo onCreate() mostraremos un mensaje para indicar cuando es creado, luego crearemos el MediaPlayer donde le asignaremos el recurso que agregamos antes, luego en el metodo onStartCommand() mostrara un mensaje de inicio y comenzara la reproduccon del audio y retornara el valor START_STICKY. El siguiente metodo es onDestroy() el cual se encargara de detener el audio reproduciendose, y por ultimo tenemos el metodo onBind() el cual retorna el valor null.

Anuncios

Con nuestra clase creada procedamos a modificar la clase MainActivity con el siguiente codigo:

package org.example.serviciosmsica;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {


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

        Button arrancar = (Button) findViewById(R.id.boton_arrancar);
        arrancar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startService(new Intent(
                        MainActivity.this,ServicioMusica.class));
            }
        });

        Button detener = (Button) findViewById(R.id.boton_detener);
        detener.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                stopService(new Intent(
                        MainActivity.this,ServicioMusica.class));
            }
        });
    }
}

En esta clase crearemos un vinculo entre los botones del layout y el codigo Java, primero crearemos el vinculo para boton_arramcar donde le diremos que inicie el servicio por medio de startService() y llamamos a la clase ServicioMusica, el siguiente vinculo sera con el boton_detener y utilizaremos a stopService() y enviara el evento a la clase ServicioMusica.

Nota: Recuerden presionar Alt+Enter para agregar a los paquetes faltantes en caso de ser necesario

Procedamos a agregar nuestra ultima modificacion, en este caso en el archivo AndroidManifest.xml para agregar el permiso necesario, para ello debemos agregar el siguiente elemento dentro de la etiqueta application:

<service android:name=".ServicioMusica" />

Con todas estas modificaciones realizadas podemos probar nuestra app, como se ve en el siguiente video

En el video podemos ver como al iniciar el servicio comenzara a reproducir nuestro archivo MP3, si lo sacamos de primer plano, la musica seguira sonando, despues vamos a ajustes, aplicaciones, buscamos las cargadas y veremos como nuestra aplicacion muestra que tambien tiene un servicio y esta activa pero si pulsamos Deterner Servicio no solo detendra la musica sino que a su vez detendra el servicio descargandolo de la memoria.

Anuncios

En resumen, hoy hemos visto que son y como trabajan los servicios, cuales son los tipos de funciones que nos permiten trabajar con los servicios, hemos repasado algunos conceptos anteriores, hemos hecho un buen ejemplo para ver como funciona, espero les haya sido util sigueme en Twitter, Facebook o Google+ para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Tambien podes donar

Es para mantenimiento del sitio, gracias!

$1.00