Capitulo 9 Del Gran Libro de Android

download Capitulo 9 Del Gran Libro de Android

of 19

Transcript of Capitulo 9 Del Gran Libro de Android

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    1/19

    263

    CAPITULO 9. Servicios y

    notificaciones

    Cuando necesites que parte de una aplicacin se ejecute en segundo pimo, debajo de otras

    actividades, y que adems no precise de ningn lipo de interaccin con el usuario, la opcin ms

    adecuada es crear un servicio Un servicio puede estar en ejecucin indefinidamente, o podemos

    controlarlo desde una actividad. A lo largo de este capitulo aprenderemos las facilidades

    proporcionadas por Android para la creacin de servicios.

    Por otra parte, las notificaciones de la barra de estado constituyen un mecanismo de comunicacin

    vital en Android. Permite a las aplicaciones que corren en un segundo plano adviertan al usuario sobre

    alertas, avisos o cualquier tipo de informacin. Las notificaciones se representan como pequeos

    conos en la barra superior de la pantalla y se utilizan habitualmente para indicar la llegada de un

    mensaje, una cita de calendario, una llamada perdida o cualquier otra incidencia de inters al usuario.

    Se trata de una comunicacin que no requiere una interaccin inmediata del usuario; este puede estar

    utilizando otra aplicacin sin ser interrumpido o puede no estar utilizando el telfono en ese momento

    Este hecho hace de las notificaciones un mecanismo de comunicacin ideal para un servicio. Por lo

    tanto, este capitulo parece el sitio ideal para describir cmo podemos crear nuestras propias

    notificaciones y utilizarlas desde nuestras aplicaciones.

    9.1. Introduccin a los servicios en Android

    Los diferentes ejemplos mostrados hasta el momento construan uni aplicacin concatenando una

    serie de actividades, cada una de las cuales permilia construir un elemento de interaccin con el

    usuario. En otros casos, ser necesario aadir un nuevo elemento a tu aplicacin, pero que no requiera

    una interaccin directa con el usuario. Este es el momento de crear un servicio.

    En Android los servicios tiene una doble funcin:

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    2/19

    264

    La primera funcin permite indicar al sistema que el elemento que estamos creando ha de ejecutarse en

    segundo plano, normalmente durante un largo perodo de tiempo. Este tipo de servicios son iniciados

    mediante el mtodo startservice (), que ndica al sistema que lo ejecute de forma indefinida hasta que

    alguien le indique lo contrario.

    La segunda funcin permite que nuestra aplicacin se comunique con otras aplicaciones, para lo

    cual ofreceremos ciertas funciones que podrn ser llamada desde otras aplicaciones. Este tipo de

    servicios son iniciados mediante el mtodo bindServce O, que permite establecer una conexin con

    el servicio e invocar alguno de los mtodos que son ofrecidos.

    Cada vez que un servicio es creado por alguna de las razones anteriores, el sistema instancia el servicio

    y llama al mtodo onCreate (). Corresponde al servicio implementar el comportamiento adecuado,

    habitualmente crear un hilo de ejecucin (thread) secundario donde se realizar el trabajo.

    Un servicio en s es algo muy simple, en este captulo se vern ejemplos de servicios locales

    escritos en muy pocas lineas. No obstante, tambin pueden complicarse, como veremos al final del

    capitulo cuando tratemos de invocar ser/icios remotos por medio de una interfaz AIDL.

    Un servicio, como el resto de componentes de una aplicacin, se ejecuta en el

    hilo principal del proceso de la aplicacin. Por lo tanto, si el servicio necesita un

    uso intensivo de CPU o puede quedar bloqueado en ciertas operaciones, como

    uso de redes, debes crear su propio hilo. Tambin puedes utilizar la clase

    ' para lanzar un servicio en su propio hilo.

    9.1.1. Ciclo de vida de un servicio.

    1

    6 importante que recuerdes que un servicio tiene un ciclo de vida diferente a una actividad. Acontinuacin, podemos ver un grfico que ilustra el ciclo de vida de los servicios:

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    3/19

    265

    Figura 6.Ciclo de vida de los servicios

    Como acabamos de explicar existen dos tipos de servicio:; segn como hayan

    Sido creados. Las funciones de estos servicios son diferentes y poi lo i., tambin su ciclo de vida.

    Si el servicio es iniciado mediante start sev ice() el sistema comenzara crendolo y llamando a

    su mtodo onCreat e() A continuacin llamara asu mtodo onStart Command (In ten t incent., intflags, in t s ta rt Id) con argumentos proporcionados por el cliente. El servicio continuar en

    ejecucin hasta que sea invocado el mtodo stopService() o stopSelf().

    Nota:Si se producen varias llamadas a sta r t Serv i ce ( )no Supondrla creacin de varios

    servicios, aunque si que se realizarn mltiples ll amadas a

    onStartComand(). No importa cuntas veces els e r v i c i o haya sido creado, parara con la

    primera invocacin de stopServ ic e()o stopSe lf () Sin embargo, podemos utilizar el mtodo

    stopSelf (i nt start Id para asegurarnos que elservicio no parar hasta que todas las llamadas

    hayan sido procesadas

    Cuando se inicia un servicio para realizar alguna tarea en segundo plano, el proceso donde seejecuta podra ser eliminado ante una situacin de baja

    En versiones del API inferiores a 2.0 el mtodo llamado ser versiones recientes se mantiene

    por razones de compatibilidad.

    Servico creado por startService()

    onCreate

    onstart()/onStartComand()

    Servico creado por bindService()

    onCreate

    onBind()

    Corrriendo Conectado

    Desconecta

    DestruirDestruido

    onDestroy()

    onDestroy()

    onUnBind() onRebind()

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    4/19

    266

    memoria. Podemos configurar la forma en que el sistema reaccionar ante estacircunstancia segn el valor que devolvamos en onStartCommandO, Existen dos modosprincipales: devolveremos start_STICKY si queremos que el sistema'trate de crear denuevo el servicio cuando disponga de memoria suficiente. Devolveremosstart_not_STICKTV si queremos que el servicio sea creado de nuevo solo cuando llegueuna nueva solicitud de creacin.

    Teniendo en cuenta que los servicios pueden estar largo tiempo en ejecucin, el ciclo devida del proceso que contiene nuestro servicio es un asunto de gran importancia. Convieneaclarar que en situaciones donde el sistema necesite memoria conservar un servicio siempreser menos prioritario que la actividad visible en pantalla, aunque ms prioritario que otrasactividades en segundo plano. Dado que el nUmero de actividades visibles es siemprereducido, un servicio solo ser eliminado en situaciones de extrema necesidad de memoria.

    Por otra parte, si un cliente visible est conectado a un servicio, el servicio tambin serconsiderado como visible, siendo tan prioritario como el cliente. En el caso de un procesoque contenga varios componentes, por ejemplo una actividad y un servicio, su prioridad seobtiene como el mximo de sus componentes.

    Podemos tambin utilizar bindServicedntent servicio, ServiceConnectioiicbriexion, int flags) para obtener una conexin persistente con un servicio. Si dichoservicio no est en ejecucin, ser creado {siempre que el flag sirvo auto crate estactivo), llamndose al mtodo onCreatet). pero no se llamar a onStartCommandO . Ensu lugar se llamar al mtodo onBindUntent intento) que ha de devolver al cliente unobjeto IBindes: a travs del cual se podr establecer una comunicacin entre cliente y

    servicio. Esta comunicacin se establece por medio de una nterfaz escrita en AIDL, quepermite el inlercambio de objetos entre aplicaciones que corren en procesos separados. Elservicio permanecer en ejecucin tanto tiempo como la conexin est establecida,independientemente de que se mantenga o no la referencia al objeto iBinder.

    Tambin es posible disear un servicio que pueda ser arrancado de ambas formas(startservice t! y bindService ()). Este servicio permanecer activo se fia sido creado desde laaplicacin que lo contiene o si recibe conexiones desde otras aplicaciones.

    Todo servicio terminar llamando al mtodo onDeatroyO cuando vaya a terminar deforma efectiva.

    9.1.2. Permisos

    Podemos conseguir que el acceso global a un servicio declararlo en la etiquetaservice* de AndroidManifeat.xml. Tambin podemos definir un permiso para restringirsu acceso. En este caso, las aplicaciones han de declarar este permiso, con elcorrespondiente uses-permission.-. en su propio manifiesto.Podemos definir un permiso para arrancar, parrar o conectarse a un servicio De formaadicional, podemos restringir el acceso a funciones especificas de las

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    5/19

    267

    ofertadas por un servicio. Para este propsito,

    podemos llamar al principio de nuestra funcin a checkCaliingPermission string! paraverificar si el cliente dispone de un permiso en concreto.

    Para ms informacin sobre permisos se recomienda la lectura del CAPTULO6.

    9.2. Un servicio para ejecucin en segundo plano.

    Dentro de los dos usos de un servicio, el ms frecuente es permitirnos ejecutar parte denuestra aplicacin en segundo plano. En una situacin tipica todos los componentes de unaaplicacin se ejecutan en un mismo proceso, a menos que se indique de forma explcita locontrario.

    Cuando nos encontramos en esta situacin, asumiendo que todos los componentes deuna aplicacin corren en el mismo proceso, se comunica de forma significativa lacomunicacin entre los diferentes componentes. Los cliente;, pueden simplemente coger eliBinder recibido del servicio y realizar un cambio do tipo (type cast) a una clase concretapublicada por el servicio.

    Otro asunto ser comunicarnos con servicios que corren en procesos diferentes al nuestro.La comunicacin entre procesos ser estudiada al final del capitulo.

    Veamos un ejemplo de servicio que corre en el mismo proceso de la aplicacin que loutiliza. El servicio ser creado con la finalidad de reproducir una msica de fondo y podr serarrancado y detenido desde la actividad principal. Crea un nuevo proyecto con los siguientesdatos:

    Projct rame: ServicioMusica

    Bu i Id Target: Android 2.0Application ame: Servicio de Msica

    Package name: org.example.aerviciomueica Crate

    Activity: ActividadPrincipal

    Min SDK Versin: 5

    Reemplaza el cdigo del layoutmain.xml por:

    eliinearLayout

    xmlns : android"http: / / schemas. andr ici. caro/ apk/ res /andri o'"android:orientation="vertical "android:layout_width="fill_parent"android : 1 a y out_height = " f ill parent ">

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    6/19

    268

    android: layout_height= "C ON T E N T "

    android: text- "Servicio D E R E P R O D U C I O N ' D E M S IC A" /

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    7/19

    269

    Button detener = (Button) findViewByld(R.id.boton_detener) ,;

    detener.setOnClickListener(new OnClickListener() ( public void onClick(View

    view)' (

    stopService(new Intent(ActividadPrincipal.this, ServicioMusica.class));

    }};

    }}

    Crea la nueva clase, ServicioMusica, con el siguiente cdigo:

    @ override

    public void onCreate0 j

    Toast. .make(this, "Servicio creado" ,Toast . LENGTH_SHORT) . show ( )

    reproductor . MediaPlayer . create ( this . H. raw . A U D IO ) ;@Override

    public int onStartCoomand(Intent intento, int Hag::, int idArranque){

    Toast.makeText(this,"Servicio arrancado " < idArranque,Toast . LENGTH_SHORT) . show ();

    reproductor.start () ; return

    START_STICKY;

    }

    @Override

    public void onDest roy ) |

    T o a s t . EAKE TE X T (this. "Servicio detenido".Toast. Length_SHORT).show();

    reproductor.stop ();

    }

    @Override

    public IBinder onBindtIntent intent return null;

    }}

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    8/19

    270

    Edita e l f i chero androidMani fes t .xml y aade la s iguiente l inea dentro de

    la et iqueta

    Crea una nueva carpeta con nombro raw dentro de la carpeta res.Arrastra

    a su inter ior e l f i chero audi o. mp3

    Ejecuta la apl i cac in y comprueba su func ionamiento. Ver i f i ca q ue

    aunque pulses var ias veces e l botn "Arrancar servic io" , es te no vuelve a

    crearse , pero s i que vuelve a l lamarse a l mtodo onStartCommandt).

    Adem s , con s olo una vez q ue puls es en " D et ene r s ervi c io" es t e pa ra r .

    Hay que tener en cuenta un problema de compat ib i l idad. El mtodo

    onStartComand0 aparece a part i r de l n ive l de API 5 , en sust i tuc in de

    onStart()! . S i t rabajas con una vers in in fer ior a la 2 .0 , reemplaza es te

    mtodo por e l cdigo s iguiente:

    @override

    Public void onStart(Intent intent, int startId){

    Toast.makeText(this,Servicio arrancado + startId,

    Toast .LENGTH_SHORT). Show();

    Reproductor.start();

    }

    Si lo comparas con onStartConimand(), este l t imo t iene un parmetro

    ms y permite devolver un resul tado. Vemoslos con ms deta l le , dado

    que sus parmetros pueden ser ut i l i zados para obtener in formacinva l iosa:

    public int onStartComand (Intent intent, int lags, int idArrantjue)

    l lamandocada vez que un c l iente in ic ia l i za un servic io mediante e l

    mtodo Los parmetros se deta l lan a cont inuac in:

    intento Un objeto intent que se indic en la l lamada

    atartService(Intent;)

    f lags Informacin sobre como comienza la so l i c i tud Puede ser 0 ,

    STARTflagREDELIVERY O START FIAG RETRY. Un VA L OR dis t intode 0 se ut i l i za para re in ic iar un servic io tras detec tar

    a lgn problema

    idArranque Un entero nico representando la so l i c i tud de arranqueespec f i ca Usar es te mismo es tero en e l mtodo s topSel fResul t ( int

    idArranque) ;

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    9/19

    271

    r e t o r na D e s c r i be c mo ha de c ompor t a r s e e l s i s t e ma c ua ndo e l p r oc e s o de l

    s e r v i c i o s e a ma t a do una ve z que e l s e r v i c i o ya s e ha i n i c i a l i z a do . E s t o pue de

    ocur r i r en s i tuac iones de ba ja memor ia . Los s igu ien te s va lore s e s tnpe rmi t i dos :

    start sticky: C ua ndo s e a pos i b l e e l s i s t e ma t r a t a r de r e c r e a r e l s e r v i c i o , s e

    realizar una llamada a onStartCommand () pero con el parmetro intento igual a null.

    E s t o t i e ne s e n t i do c ua ndo e l s e r v i c i o pue de a r r a nc a r s i n i n f o r ma c i n a d i c i ona l ,

    c omo po r e j e mpl o , e l s e r v i c i o mos t r a do pa r a l a r e p r oduc c i n de ms i c a de

    fondo. start_ n o t _sticky: E l s i s t e ma no t r a t a r de vo l ve r a c r e a r e l s e r v i c i o , po r l o

    ta nt o el pa rm etr o intento nun ca p odr ser i gua l a null.. Es to t i ene sen t ido

    c ua ndo e l s e r v i c i o no pu e de r e a nuda r s e una ve z i n t e r r umpi do .

    start redeuIver intent: E l s i s t ema t r a ta r de vo lve r a c rea r e l s e rv ic io . E l

    pa r me t ro intento s e r e l qu e s e u t i l i z en l a l t i mal l a ma da startservice (Intent).

    STAPT_STICKY_COMPATIBILITy" : V e r s i n c ompa t i b l e de s t a r t sticky, que no

    ga r a n t i z a que onstartcomnandl) s e a l l a ma do de s pu s de que e l p r oc e s o s e a ma t a do .

    9.3. Las notificaciones de la barra de estado

    La ba r ra de e s tado de Andro id se encuent ra s i tuada en l a pa r te supe r ior de

    l a pa n t a l l a . L a pa r t e i z qu i e r da de e s t a ba r r a e s t r e s e r va da pa r a v i s u a l i z a r

    no t i f i c a c i one s. C ua ndo s e c r e a una nue va no t i f i c a c i n , a pa r e c e un t e x t ode s p l a z ndos e e n l a ba r r a , y a c on t i nua c i n , un pe que o i c ono pe r ma ne c e r e n

    l a ba r r a pa r a r e c o r da r a l u s ua r i o l a no t i f i c a c i n .

    E l u s ua r i o pue de a r r a s t r a r l a ba r r a de no t i f i c a c i one s ha c i a a ba j o , pa r a

    mos t r a r e l l i s t a do de l a s no t i f i c a c i one s po r l e e r . U n pos i b l e e j e mpl o s e

    mue s t r a a c on t i nua c i n :

    http://stapt_sticky_compatibh.it/http://stapt_sticky_compatibh.it/http://stapt_sticky_compatibh.it/http://stapt_sticky_compatibh.it/http://stapt_sticky_compatibh.it/http://stapt_sticky_compatibh.it/http://stapt_sticky_compatibh.it/
  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    10/19

    272

    Una notificacin puede ser creada por un servicio o por una actividad. Aunque dado que la actividad

    dispone de su propio interfaz de usuario, parece que las notificaciones son el mecanismo de interaccin

    ms interesante del que disponen los servicios. Las notificaciones pueden crearse desde un segundo

    plano, sin interferir con la actividad que en ese momento est utilizando el usuario.

    Para crear una notificacin en la barra de estados has de seguir los siguientes pasos. Aade el

    cdigo de ejemplo a la clase S erv i c i oM u s i ca .

    1) Obtenuna referencia al Not i f i cat ionManager . Para ello, declara las siguientes variables y

    aade al mtodo onCreate

    prvate N o t i f i c a t i o n M a n a g er tn

    p r va t e s t a t i c . f i n a l i n tID_NOTIFICACION_CREAR

    = 1 ;

    @override

    public voidon C reat e ( ) {

    n m = ( N ot i f i ca t ion M an ager ) ge tS ys t em S erv i ce {NOTIF ICAT10N_SERVICE) ;

    2) Instancia una nueva notificacin:

    Notif icat ion not i f icacin = new Noti f icat ion (

    R .drawable . i c on ,

    " crean d o S erv i c i o d e M s i ca" ,

    Sys tem , currentTimeMillis( ) ) ;

    Como puedes ver, en el constructor de una notificacin hay que indicar 3 parmetros: el icono a

    visualizar (en el ejemplo usamos el mismo que el de la aplicacin), el texto a mostrar y cuando

    queremos que se visualice (en el ejemplo indicamos que ahora mismo).

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    11/19

    273

    3) Define informacin adicional que ser utilizada en la ventana de notificaciones. Esta informacin

    incluye el mensaje expandido y la actividad a ejecutar cuando se pulse sobre la notificacin:

    Pe nd i ng l n t en t i n t e n t oPe nd i e n t e = Pe nd i ng I n t e n t .getActi vit y (

    th i s , 0 , new In ten t ( th i s , Ac t iv idadPr in c ipa l . c la s s ) , 0 ) ;

    no t i f i c a c i n . s et L a t e s t E ve n t I n f o( t h i s , "R e pr oduc i e ndo ms i c a " ,

    " i n f o r ma c i n a d i c i ona l " , i n t e n t oPe nd i e n t e ) ;

    Cuando el usuario abra la ventana de notificaciones, podr ver informacin adicional formada por

    un ttulo y un texto explicativo. Adems se podr asociar una actividad para que se ejecute cuando

    el usuario pulse sobre la notificacin. En el ejemplo se crea un Pendinglntent asociado a la

    actividad A ct i v i d ad P r i n f c i p a l . Por supuesto, tambin puedes crear una nueva actividad

    para usarla exclusivamente con este fin. En un ejemplo ms complejo, puedes pasar los parmetros

    adecuados a travs del i n t en c , para que la actividad conozca los detalles especficos que

    provocaron la notificacin (por ejemplo, el nmero de telfono que provoc la llamada perdida).

    Una notificacin puede tener otros parmetros, por ejemplo, puede reproducir un sonido, puede

    hacer vibrar el telfono o puede hacer parpadear un LED del telfono. Puedes consultar el

    siguiente punto si ests interesado en alguno de estos aspectos.

    4) Pasa la notificacin creada al Not i f i cat ionManager:

    nm.not i fy ( ID_NOTIFICACION_CREAR. no t i f i c a c i n ) ;

    ! . . . / / r e s t o de c d i go de onc r e a t e ( )

    5) Si el servicio deja de estar activo, eliminamos la notificacin:

    @Override

    pu b l i c vo id onD e s t r oy( ) (

    nm. c a nc e l {1D_N0TIFICACI0N_CREAR) ;

    Este paso es opcional. Muchas notificaciones han de permanecer .visibles aunque el servicio quelas creo sea destruido. En nuestro caso, dado que estamos anunciando que un servicio de

    reproduccin de msica est activado, la notificacin deja de tener sentido al desaparecer el

    servicio.

    9.3.1. Configurando tipos de avisos en las notificacionesComo hemos comentado una notificacin puede utilizar diferentes mtodos para alertar al

    usuario de que se ha producido. Veamos algunas opciones.

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    12/19

    274

    9.3.1.1. Asociar un sonido

    Si consideras que una notificacin es muy urgente y deseas que el usuario pueda conocerla de forma

    inmediata, puedes asociarle un sonido que ser reproducido cuando se produzca.

    El usuario puede definir un sonido por defecto para las notificaciones. Si quieres asociar el sonido

    de notificaciones por defecto, utiliza la siguiente sentencia'

    notificacion.defaults = Notificacin.DEFAULT SOUND;

    Si prefieres reproducir un sonido personalizado para la notificacin, puedes almacenarlo en una carpeta

    y usar:

    notificacin.sound - Uri.parpe("file://'sdcard/carpeta/tono.mp3";

    Si el fichero de audio se encuentra almacenado en el ContentProvider MediaStore. puedes utilizar

    la siguiente sentencia:

    notificacion.sound =

    Uri.withAppendedPath(Audio.Media.INTERNAL CONTENT ORI, "6");

    Tendrs que sustituir el parmetro 6" por el ID del elemento que quieras reproducir. Si desconoces

    este ID, puedes realizar una consulta al ContentProvider Para ms informacin consulta el apartado

    7.6.

    9.3.1.2. Aadiendo vibracin

    Tambin es posible alertar al usuario haciendo vibrar el telfono. Puedes utilizarla vibracin por defecto:

    notificacin .defaults |= Notification . DEFAULT_VIBRATE ;

    O por el contrario tu propio patrn de vibracin:

    Long()vibrate = {0,100,200,300}; notication.vibrate

    =vibrate;

    El array define un patrn de longitudes expresadas en milisegundos; donde el primer valor es el

    tiempo sin vibrar, el segundo es el tiempo vibrado, el tercero sin vibrar y asi sucesivamente. Este array

    puede ser tan largo como queramos, pero solo ser activado una vez. no se repetir de forma cclica.

    9.3.1.3. Aadiendo parpadeo de LED

    Algunos mviles disponen de diodos LED que pueden ser utilizados para avisar al usuario que se ha producido una

    notificacin. Este mtodo es muy interesante si el grado de urgencia del aviso no es lo suficientemente alto para usar uno

    de los mtodos anteriores.

    Podemos utilizar el aviso de LED configurado por defecto:

    http://%27sdcard/carpeta/tono.mp3http://%27sdcard/carpeta/tono.mp3http://%27sdcard/carpeta/tono.mp3http://%27sdcard/carpeta/tono.mp3
  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    13/19

    275

    Notification.defaults |=notification.DEFAULT_LIGHTS;

    O podemos definir una cadencia de tiempo y color especfica para nuestra notificacin:

    Notification.ledARGB=0xff00ff00;

    Notification.ledOnMS=300;

    Notification.ledOffMS=1000;

    Notification.flags | =Notification.FLAG_SHOW_LIGHTS;

    En el ejemplo anterior se empieza indicando que queremos que el LED se ilumine en color verde, durante 300 ms y

    luego est apagado durante 1 segundo. Esta secuencia se repetir de forma cclica hasta que el usuario atienda la

    notificacin.

    Conviene destacar que no todos los mviles disponen de un LED para este propsito. Adems, no todos los colorespueden ser utilizados, siendo e! color verde el ms habitual para indicar una notificacin.

    9.4. Un servicio comomecanismo de comunicacin entre aplicaciones

    Como hemos comentado, un servicio tiene una doble funcionalidad, adems de permitir la ejecucin de cdigo en

    segundo plano, vamos a poder utilizarlo como un mecanismo de comunicacin entre aplicaciones .

    Cuando una aplicacin quiere compartir algn tipo de informacin a otra aplicacin se presenta un problema. Las

    aplicaciones en Android se ejecutan en procesos separados y por tanto tienen espacios de memorias distintos. Esio nos

    impide, por ejemplo, que ambas aplicaciones compartan un mimo objeto.

    Como respuesta a este problema Android nos propone un mecanismo de comunicacin entre procesos que se basa

    en un lenguaje de especificacin de nterfaces, AIDL, que son publicados por medio de servicios.

    AIDL [Android Interface Definition Language) es un lenguaje de especificacin de interfaces que permite que un

    proceso en Android pueda liamar a un mtodo de un objeto situado en un proceso diferente al suyo. Se trata de un

    mecanismo de comunicacin entre procesos similar a COM o Corba, aunque algo ms ligero.

    S queremos comunicar dos aplicaciones a travs de este mecanismo seguiremos los siguientes pasos:

    1) Escribiremos un fichero AIDL: En el se define la interfaz. es decir los mtodos y los parmetros que luego

    podremos utilizar

    6http://developer.android.eom/quide/topics/fundamentals.html#rpc

    http://developer.android.eom/quide/topics/fundamentals.html%23rpchttp://developer.android.eom/quide/topics/fundamentals.html%23rpchttp://developer.android.eom/quide/topics/fundamentals.html%23rpchttp://developer.android.eom/quide/topics/fundamentals.html%23rpc
  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    14/19

    276

    2) Implementaremos los mtodos de la interfaz: Para ello, habr que crear unaclase en Java que implemente estos mtodos

    3) Publicar la interfaz a los clientes: Para ello, se extender la clase servicesobrescribiremos el mtodo OnBind(intent) de forma que devuelva una instancia de laclase que implementa la interfaz.

    Veamos estos tres pasos ms detenidamente por medio de un ejemplo. Para ello, crea la

    siguiente aplicacin:

    Proiect name: Servicio-Remoto

    Bui Id Target: Android 2.0

    Application name: Servicio Remoto

    Package ame: org.example.serviciocliente

    Create Activity ActividadPrincipal

    Min SDK Versin: 5

    Reemplaza el cdigo del Layout main.xml por el mismo utilizado en ServicioMusica.Reemplaza los textos de los botones "Arrancar servicio" por"Conectar servicio" y "Detenerservicio" por"Desconectar servicio". Crea dos botones ms. Uno con texto "Reproducir" e id"@*-d/boton_reproducir" y otro con texto "Avanzar" e id "@+id/boton_avanzar".

    Copia el fichero res/raw/audio.mp3 a la nueva aplicacin.

    9.4.1. Crear la interfaz en AIDL

    El lenguaje de especificacin de interfaces AIDL, tiene una sintaxis similar a Java,aunque como su nombre permite nicamente identificar la interfaz de un objeto no suimplementacin.

    Una interfaz estar formado por una secuencia de mtodos cada uno con una serie deparmetros y un valor devuelto. Tanto los parmetros como el valor devuelto han de tener untipo. Los tipos permitidos se indican a continuacin:

    Tipos primitivos: int, short, byte,char, float, double,long, Boolean.

    Uno de los siguientes tipos: string, CharSequence, List, Map.

    Una interfaz escrito en AIDL.

    Un Objeto Parcelable.

    Para seguir con el ejemplo, crea un nuevo fichero con nombre

    IServicioMuaica . a idl dentro de arc/org.example. servicioaidl/ con el siguiente cdigo:

    package org.example.servicioremoLo; interface IServicioMusica {

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    15/19

    277

    String reproduce(in String mensaje);

    void setpPosicon (int ms);

    int get.Posicion ();

    }

    Como puedes observar la sintaxis es similar a Java aunque existen diferencias. La msdestacable consiste en que los parmetros de los mtodos cuyos tipos no sean primitivos,han de indicar la etiqueta in, out o inout; segn sean parmetros de entrada, salida o de lasdos cosas a la vez. Para los tipos primitivos solo se permite que acten como entrada, porlo tanto se procesan de forma predeterminada comoin.

    Nota: Igual como ocurre con las clases en Java los interfaces en

    AIDL han de escribirse en fichero con igual nombre que lainterfaz.

    9.4.2. Implementar la interfaz

    Un vez escrito esta interfaz y almacenado en el fichero .aidl, el P L U G - I N de Eclipsegenerar de forma automtica el fichero

    gen/org . example . serviciorernoto/IServicioMusica . java .

    Este fichero implementa la interfaz Java IServicioMusica como descendiente de

    IInterface. En IServicioMusica se define internamente la clase abstracta Stub que

    implementa la interfaz escrito en AIDL. Es decir, la clase Stub contiene tantos mtodosabstractos como mtodos declaramos en la interfaz AIDL. La clase stub tambin define unaserie de mtodos que le permiten el intercambio de informacin cuando se invoquen estosmtodos entre procesos remotos.

    Ahora tenemos que darle funcionalidad al interfaz, para ello tendremos que crear una

    clase que extienda IServicioMusica.Stub y que implemente todos los mtodos abstractos deesta clase, o lo que es lo mismo, los mtodos declarados en la interfaz AIDL. Un ejemplo decmo podramos implementar estos mtodos se muestra a continuacin. Ms tarde se indicadonde hay que introducir este cdigo:

    prva te final IServicioMusica.Stub binder = new IServicioMusica.Stub() {

    public String reproduce(String mensaje) {

    reproductor.start();

    return mensaje;

    }

    public void setPosicin (int ms) {

    reproductor.seekTo(ms);

    }

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    16/19

    278

    public int getPosicion() {

    return reproductor.getCurrentPosition()

    } };

    La variable reproductorser declarada posteriormente de tipoMediaPlayer. Como puedes ver, en

    el mtodo reproduce, tanto el parmetro de entrada como el valor devuelto no tienen ninguna

    utilidad. Se han introducido para ilustrar el paso de una variable no primitiva.

    Cuando implementes los mtodos de una interfaz AIDL has de tener en cuenta lo siguiente:

    Si generas una excepcin desde uno de estos mtodos, esta no pasar a la aplicacin que hizo lallamada

    Las llamadas son sncronas. Por lo tanto, has de tener cuidado de que cuando se haga unallamada que tarde cierto tiempo en responder, nunca se realice desde el hilo principal de la

    aplicacin. Si este hilo queda bloqueado demasiado tiempo, aparecer el incmodo cuadro de

    dilogo "La aplicacin no responde". En estos casos, crea un hilo secundario, desde donde se haga

    la llamada.

    Solo es posible declarar mtodos; no puedes declarar campos estticos en una interfaz AIDL

    9.4.3. Publicar a interfaz en un servicio

    Otras aplicaciones han de tener visible esta interfaz para poder comunicarse con nosotros. Esto se

    consigue creando un servicio que contenga nuestra interfaz.

    Para ello has de crear una clase que herede de Service y que reescriba el mtodoencina O . Este

    mtodo ser utilizado para devolver un objeto que implementa nuestra interfaz. Veamos cmo se

    escribira este servicio:

    public class ServicioRemoto extends Service{ MediaPlayer

    reproductor;

    public void onCreateO (

    super.onCreate() ;

    reproductor =MediaPlayer.create(ServicioRemoto.this, R.raw.audio);

    private final IServicioMusca.Stub binder new IServicioMusica.Stub(){

    // Copia agu. e.lcdigo anterior

    };

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    17/19

    279

    @Override

    public IBinder onBind(Intent intent){

    return this.binder;}

    }

    Crea una nueva ciase en el proyecto e introduce este cdigo. Para que el servicio sea visible a otras

    aplicaciones hay que publicarlo declarndolo enAndroidManitest.xml. Para ello copia el siguiente

    cdigo dentro de la etiqueta

    .

    < servicios android:name="ServicioRemoto"

    android:process=":remoto">

    El atributo name ha de coincidir con la clase que implementa el servicio. El atributoprocess

    permite que el servicio se ejecute en un proceso propio, diferente al resto de los componentes de la

    aplicacin. A continuacin, indicaremos dentro de la etiqueta

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    18/19

    280

    I S erv ic omusca. stub. asinterf ace () pasndole como parmetro esta instancia de

    iB inde r para inicializar el objeto declarado en el primer punto.5) Ya puedes llamar a los mtodos del objeto remoto declarados en el punto 1). En nuestro casoreproducir (),setPosicin () y getPosicion (I.

    6) Puedes desconectarte del servicio utilizando el mtodo u n b i n d S e r v i c e ( ) .

    Realizaremos este trabajo en la clase A c t i v i d a d P r i n c i p a i . Reemplaza su cdigo por el

    siguiente:

    public class ActividadPrincipal extends Activity {

    private IServicioMusica servicio; (1)private Servi ceConnect ion conexin= new ServceConnect ion () (2)

    public void onServiceConnected(ComponentName className (4)

    IBinder Iservicio){servicio = IServicioMusica.Stub.asInterface(Iservicio) ; Toast..MakeTexc (ActividadPrincipal. this;

    "Conectado a Servicio", Toast.LENGTH_SHORT).show();

    jpublic void onServiceDisconnected(ComponentName className) { servicio = null;

    Toast.. makeText(ActividadPrincipal. this ,

    "Se ha perdido la conexin con el Servicio", Toast .LENGTH_SHORT) .show();} }@override

    public void onCreate(Bundle savedInstanceState){| super.onCreate!saved InstanceState);

    setContentView(R.layout.main)Button botonConectar = (Button) FindViewById(R.id.boton_arrancar);

    botonConectar.setOnClickListener(new OnCi ickListener(){ ( public void onClick(Viewv) {

    Act ividadPrincipal . this , bindService ({ (3 )new intent (ActividadPrincipal.this, ServicioRemoto.class) conexion,

    Context.B1ND_AUT0_CREATE) ;}});

    Button botonReproducir= (Button! findViewById R.Id.boton_repproducir);Boton_reproducir.setOnclickListener(new OnClickistener(){

    Public void onclick(View v)}try{

    Servicio.reproduce(titulo);}Catch(exeption e){

  • 7/27/2019 Capitulo 9 Del Gran Libro de Android

    19/19

    281

    Toas Maketext(ActividadPrincipal.this,e.toString();

    Toast.LENGTH_SHORT) .showf);

    Button botonAvanzar = (Button)findViewById(R. id.boton__avanzar);

    botonAvanzar . setOnClickListener (new OnClickListener (){public void onClick(View v) { try {

    servicio.setPosicion(servicio.getPosicion() +10 00) ; (5) j catch (Exception e; |

    Toast.makeText(ActividadPrincipal.this, e.toString();,Toast.LENGTH _SHORT) .show();

    }}});

    Button botonDetener =(Button) findViewById(R.id.boton_detener) ; botonDetener . setOnCl ickListener (new OnClickListener (); {

    public void onClick;. (View v) { try

    ActividadPrincipal.this.unbindService(conexion) ; (6)

    } catch (Exception e) {Toast. makeText (ActividadPr incipal. this, r.. toString () ;

    Toast . LENGTH_SHORT) . show () ;

    }Servicio=null;

    }});}}

    La acti vidad est formada por 4 botones para realizar las acciones de conectarse alservici o, desconectarse, reproduci r msica y avanzar 1 segundo (1.000 ms). Si losbotones no se activan por el orden adecuado podemos provocar excepciones. Estas son

    capturadas y visualizadas mediante untoast , por lo que la aplicacin continuarfuncionando aunque se produzcan. Prueba a ll amar aun mtodo antes de establecer la

    conexin o tr ata de desconectar te dos veces para observar las excepciones generadas.