Está en la página 1de 14

Curso PUDE

Desarrollo de Aplicaciones Mviles en Android

Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano


Aunque ya hemos visto muchas cosas a lo largo del curso, an queda mucho por descubrir. Uno de los grandes usos que se les da a los smartphones, es el de usuarios de servicios web, o Web Services. Esto se debe a que consiguen dar una nueva vuelta de tuerca a los servicios que ya existen (Google Search, Google Maps, Google+, Facebook, Twitter, Facebook, App.Net, Instagram, Flickr, 500px, Picasa, Quora, etc.) En este ejercicio, veremos una breve introduccin sobre cmo acceder a ellos desde la plataforma Android.

A. Descripcin
El gran auge de la denominada Web 2.0 est fundada sobre la existencia de los Web Services. En esencia, un Web Service es un mtodo de comunicacin entre dos sistemas electrnicos cualesquiera sobre la Red (Internet). Para nosotros, desarrolladores de smartphones, significa que hay una serie de mquinas conectadas a Internet a las cuales podemos realizar peticiones, peticiones que volvern a nosotros en forma de respuestas. Todo esto se basa en la existencia de una serie de protocolos y estndares (HTTP, WSDL, SOAP, REST, RPC, XML, JSON, etc.) adems de una gran variedad de tecnologas (Apache, .NET, J2EE,) Pero, qu es lo que importa aqu? Primero, debemos entender que hay varias formas de comunicarse con un servidor, dependiendo del protocolo que utilice ste para comunicarse con el exterior, y lo segundo es que las comunicaciones con servicios web estn basadas en APIs. Cada proveedor de servicio web tiene su propia API, y debido a que nosotros, los desarrolladores, somos usuarios de esas APIs, debemos cumplir con ellas, y estar atentos a posibles cambios por parte de los autores, porque si no, lo pagarn nuestros usuarios. Nosotros, en este ejercicio, llamaremos a la API de codificacin geogrfica de Google. Nuestro objetivo? Pasarle una posicin GPS (Latitud, Longitud) y que Google nos diga cmo se llama la calle que se encuentra en esas coordenadas.


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 1 de 14

A.1. REST

Al igual que SOAP, REST es una arquitectura sobre la que pueden basarse los Web Services. En esencia, REST implica que el servidor no posee estado, es decir, que cada peticin que hacemos al servidor es independiente de todas las anteriores y de todas las posteriores; no hay tokens ni cookies de por medio. Esto es comn en servicios que no requieren inicio de sesin, como nuestro caso, pero por ejemplo, si quisiramos comunicarnos con Facebook para actualizar nuestro perfil, el funcionamiento sera diferente (tendramos que mantener el inicio de sesin como un token en este caso) REST, adems, resulta ser muy simple, pues posee un nmero fijo de operaciones definidas (GET, POST, PUT y DELETE), con un propsito bien definido por el protocolo. GET se utiliza para obtener algn dato, POST y PUT para subir, modificar o aadir algo al servidor, mientras que DELETE permite eliminar un dato del servidor. En la prctica sin embargo, GET y POST son ambos utilizados para obtener datos. La razn es muy simple; si alguna vez os habis fijado en las direcciones de vuestro navegador, habris visto direcciones en las que al final hay parejas (clave, valor) separadas por un ampersand (&); estas parejas son los parmetros que se le pasan al servidor, y si por ejemplo necesitamos enviar datos privados (por ejemplo: nuestra direccin), no querramos que stos navegaran abiertamente por la red. Por esta razn se utiliza el POST como alternativa al GET, ya que el POST permite enviar los parmetros como parte de su cabecera (dentro del paquete), lo cual permite esconder los datos un poco, e incluso deja abierta la posibilidad de encriptar los datos y enviarlos. En la prctica, las operaciones GET, POST, PUT y DELETE son muy comunes, y no tienen por qu ceirse a nicamente a los servicios de tipo REST; pueden ser utilizados por cualquier Web Service para que la API sea ms fcil de entender, y para mantener un cierto estndar.

B. Implementacin
Para comunicarnos con la API de Google necesitaremos realizar una peticin de tipo GET. En concreto, el servicio que vamos a utilizar es el de reverse-geocoding (codificacin geogrfica inversa), el cual nos permite obtener una direccin a partir de unas coordenadas GPS. Para ello, nos bastar con una nica Activity, un layout, y varios String. Empecemos. Nota: Para ms informacin acerca de la API que estamos utilizando, visitar http://code.google.com/intl/es-ES/apis/maps/documentation/geocoding/
Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 2 de 14

C. Pasos a seguir
1. Comenzamos creando un nuevo proyecto Android que cumpla con todos los requisitos que hemos visto desde que pasamos a nivel Intermedio, es decir: soporta versiones desde la 1.6 2.x hasta la 4.2, utiliza la librera de soporte de fragments, tiene una Activity cuya nica funcin es dar paso a un Fragment y el propio fragment con los clsicos mtodos onCreate(Bundle savedInstanceState), onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) e initView(Bundle savedInstanceState). Siempre respetando, por supuesto, la disposicin en paquetes que hemos estado viendo. (Como nombres podis utilizar RequestActivity y RequestFragment respectivamente) 2. Antes de escribir el layout, necesitaremos definir una serie de etiquetas (String): <string <string <string <string <string <string <string
3.

name="latitude">Latitud: </string> name="defaultLatitude">37.806978</string> name="longitude">Longitud: </string> name="defaultLongitude">-122.474417</string> name="result">Resultado: </string> name="getAddress">Obtener Direccin</string> name="error">Se produjo un error </string>

Para el layout del Fragment, utilizaremos un RelativeLayout como padre, que comenzar con dos parejas de combinaciones TextView/EditText (un TextView seguido de un EditText dos veces). Los llamaremos latitudeTV, latitudeET, longitudeTV y longitudeET respectivamente. Todos ocuparn la mnima altura posible pero todo el ancho disponible. Adems, daremos a cada uno un valor a su atributo text en el orden en el que se encuentran (latitude y longitude para los TextView, defaultLatitude y defaultLongitude para los EditText). El primer TextView (latitudeTV) ha de ir anclado a la parte superior de su padre (android:layout_alignParentTop="true"), y el resto se ir colocando en orden justo debajo (utilizar android:layout_below) A continuacin colocaremos el Botn para accionar la peticin; se llamar requestButton, ir en la parte inferior del layout (android:layout_alignParentBottom="true"), y ocupar el mismo espacio que las View anteriores (todo el ancho disponible, pero slo la altura necesaria). Su texto ser el de la etiqueta getAddress.


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 3 de 14

Para terminar con el layout, colocaremos otra pareja TextView/EditText ms: el TextView debe ir bajo el EditText longitudeET, mientras que el EditText ir bajo el TextView que acabamos de aadir y sobre el requestButton. El TextView ocupar el mismo espacio que los dems (altura mnima, pero todo el ancho posible), mientras que el EditText ocupar todo el espacio disponible, tanto en ancho como en alto (es decir, ocupa todo el espacio que queda entre el TextView que acabamos de colocar y el requestButton que est anclado justo en la parte inferior de la pantalla). Por ltimo, a este EditText nos interesa prepararlo para que soporte largas entradas de texto (ver atributos gravity, inputType y scrollbars. Como nombres elegiremos resultTV y resultET. El texto de resultTV debe ser el de la etiqueta result. Por ltimo, como este EditText no lo vamos a utilizar para introducir datos, sino para mostrarlos, nos convendra hacer lo posible para que el usuario no pueda modificarlo (android:enabled="false").

4. Resulta que el cdigo anterior para bloquear el resultET funciona tal y como queremos en todas las versiones de Android hasta la 4.0.3 (API versin 15); esto es porque a partir de esta versin, si deshabilitamos una View, sta ya no recibe interacciones, por lo que nuestro resultET no sera navegable. La solucin resulta obvia: encapsular el resultET dentro de un ScrollView, pero en lugar de eso, preferimos buscar una solucin que rodee este problema para hacer algo nuevo: otro layout nicamente para las versiones afectadas. Lo hacemos creando una nueva carpeta, la layout-v15, donde copiamos nuestro main_fragment.xml existente. Ahora, solamente tenemos que hacer la adaptacin en el layout correspondiente, y Android se encargar de todo. 5. Una vez hayamos comprobado que el layout carga correctamente (podemos dejar la comprobacin de las distintas versiones para ms adelante), empezaremos a escribir cdigo en nuestro Fragment. Nuestro objetivo es utilizar los dos primeros EditText para introducir las coordenadas GPS, el botn para realizar la peticin, y el ltimo EditText para mostrar la salida. Por tanto, necesitamos variables que nos permitan referenciar estas Views; necesitaremos una referencia a latitudeET, longitudeET, un requestButton y un resultET, todos son sus tipos correspondientes (llamar las variables de la misma forma). Utilizaremos nuestro mtodo initConfig(ViewGroup viewGroup) para referenciar las views. A continuacin, aadiremos un onClickListener al requestButton y haremos que el anterior llame a un mtodo llamado makeRequest() sin argumentos. En este mtodo implementaremos la peticin a la API de Google MAPS.


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 4 de 14

6. Escribimos la cabecera del mtodo privado makeRequest() sin argumentos y sin ningn valor a devolver. Lo primero que debemos hacer en l es desactivar los EditText y el Button para que el usuario no pueda realizar modificaciones ni llamar a este mtodo ms de una vez al mismo tiempo. Al final del mtodo, escribimos el cdigo contrario, es decir, el que vuelve a activar los EditText y el requestButton. 7. El cdigo importante viene aqu. En medio del mtodo makeRequest() ( tras desactivar los EditText y el requestButton ) debemos aadir un bloque try/catch genrico (que capture cualquier Exception). Dentro del bloque try/catch, introduciremos el siguiente cdigo:
// obtenemos una conexin DefaultHttpClient httpClient = new DefaultHttpClient(); String url = "http://maps.googleapis.com/maps/api/geocode/json?latlng=" + latitudeET.getText().toString() + "," + longitudeET.getText().toString() + "&sensor=false"; // creamos una peticin de tipo GET (parmetros en la URL) HttpGet request = new HttpGet(); request.setURI(new URI(url)); // ejecutamos la peticin HttpResponse response = httpClient.execute(request); // convertimos la respuesta en string String responseString = EntityUtils.toString(response.getEntity()); // escribimos el resultado resultET.setText(responseString); // cerramos la conexin httpClient.getConnectionManager().shutdown();


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 5 de 14

8. Con este cdigo en posicin la aplicacin debera funcionar correctamente. O no? Nos hemos olvidado de algo? S. Queremos realizar una peticin en Internet, luego nos hace falta el permiso (<uses-permission>) INTERNET en el manifest de nuestra aplicacin. 9. Si ejecutamos la aplicacin con una API inferior a Honeycomb (3.0), la aplicacin retorna un resultado muy largo, dentro del cual se encuentra la direccin del calle del Puente del Golden Gate en San Francisco, pero, qu es todo este texto que recibimos como respuesta? Y lo que es ms importante an, por qu se detiene la aplicacin mientras realiza la peticin, y por qu obtenemos un error si en un dispositivo con Honeycomb o superior?

B (2) Ejecucin en segundo plano


Detengmonos un segundo a mirar lo que acabamos de hacer. Android posee varias libreras incluidas, y una de ellas (HttpClient), es la que hemos utilizado para obtener acceso a Internet. Puede verse que primero necesitamos inicializar un objeto de tipo HttpClient y que luego, al final de la peticin lo apagamos ( mtodo shutdown() ). En este ejercicio hemos querido simplificar el cdigo lo mximo posible para centrarnos en lo importante: entender cmo implementar comunicaciones con Web Services, pero en realidad,
Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 6 de 14

el hecho de inicializar y de cerrar clientes HTTP es una operacin costosa, y en aplicaciones que requieran de acceso a Internet a lo largo de muchas Activity lo recomendado es compartir un nico HttpClient compartido, y que ste se cierre nicamente cuando el usuario ya no est utilizando la aplicacin. Lo siguiente a tener en cuenta es la respuesta. Como ya hemos mencionado, nuestro Web Service en cuestin posee su propio protocolo, uno al que ya nos hemos adaptado (en parte) al realizar la peticin (ntese que los parmetros estn en la URL), sin embargo, la sorpresa viene al ver que la respuesta no nos da los datos de forma directa, ni mucho menos. La respuesta que tenemos es en realidad un objeto JSON (JavaScript Object Notation), al que muchos nos gusta llamar el sucesor del XML. Lo comn cuando se interacta con Web Services es recibir la respuesta o bien en formato XML, o bien en formato JSON. XML tiene la ventaja de ser muy conocido y de que es increblemente flexible, adems de que est soportado por casi todos los lenguajes. Sin embargo, tiene una gran desventaja con respecto al JSON, y es que requiere de la construccin de un parser, un analizador o escner, especfico para cada tipo de documento XML. Esto significa que para un mismo Web Service, podramos tener que escribir dos o ms escneres, uno por cada peticin distinta que tengamos que hacer (en la prctica, los Web Service intentan minimizar que esto ocurra). Es aqu donde gana el ms moderno JSON: funciona por parejas (clave, valor), se adapta a cualquier estructura, cada vez es ms soportado, y adems, no requiere construir un parser especfico, solamente adaptarnos a la respuesta recibida.

Lo ms importante, sin embargo, es el hecho de que nuestra aplicacin se detiene cada vez que realiza la peticin. Con detenerse queremos decir que, si nosotros interactuamos con la aplicacin mientras est realizando la llamada al Web Service, sta no es capaz de hacernos caso. Por qu? La respuesta es muy simple: porque est ocupada.

Hasta ahora, todas las acciones que hemos realizado en Android han sido acciones rpidas, sin apenas retardo ni complejidad; esto ha permitido que pasemos por alto un hecho muy importante: hemos estado utilizando el hilo (thread) encargado de procesar los eventos de la interfaz grfica para todas nuestras acciones.

Es decir, la secuencia de instrucciones que mantiene viva nuestra aplicacin, respondiendo cada vez que nosotros presionamos la pantalla, pulsamos un botn, o simplemente deslizamos un dedo para ver cmo se ilumina una parte de la pantalla, es la misma que ejecuta todas y cada una de las lneas de cdigo que hemos programado hasta ahora (eventos, creacin de mltiples Activity y Fragments, la rotacin y todo lo que ello conlleva, etc.) han detenido brevemente la capacidad de la aplicacin de responder ante nuestras peticiones, pero debido a que le hemos pedido relativamente poco al hilo de la interfaz grfica, no nos hemos dado cuenta.

Todo ha cambiado con la peticin al Web Service, donde dependiendo del dispositivo y de la Red se detiene por completo el procesamiento de eventos en la aplicacin, includos todos los que provoque el usuario al tocar la pantalla o presionar un botn. De hecho, si una interaccin por parte del usuario tarda ms de medio segundo en producirse, un usuario
Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 7 de 14

medio se da cuenta, y a los cinco segundos, Android le permite cerrar la aplicacin mostrndole un dilogo conocido como ANR o Application Not Responding . Para mejorar la calidad del software servido por Google Play en general, a partir de Honeycomb todas las llamadas que involucren una conexin a Internet provocan una excepcin por parte del Sistema Operativo que nos indica precisamente eso, que estamos conectando con otra mquina a travs de Internet desde el hijo principal o de interfaz de usuario de la aplicacin; por esto es por lo que la aplicacin nos falla en estas versiones. La solucin? Mover las partes de cdigo lentas a otro hilo, uno secundario, que pueda realizar estas acciones en paralelo. Mientras tanto, el hilo de la interfaz mantendr la aplicacin viva, y cuando el hilo secundario termine, podr notificar al primer hilo para que actualice la interfaz. Hagmoslo.

C (2) Pasos a seguir


1. Debemos crear un nuevo paquete, esta vez para guardar las clases de tipo Thread. Una vez creado, pediremos a Eclipse que aada una nueva clase, RequestThread, que heredar de la clase java.lang.Thread. 2. La clase RequestThread estar vaca. Los datos que necesitamos son la latitud, la longitud y un Handler. Un Handler es un objeto de Java capaz de recibir mensajes (eventos) de forma asncrona, es decir, sin detener el hilo de ejecucin desde el que fue llamado. Adems, funciona muy bien cuando se le llama desde un hilo distinto. Comenzamos aadiendo estas lneas de cdigo a la cabecera de la clase RequestThread:

private Handler myHandler; private String latitude; private String longitude;


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 8 de 14

3. A continuacin, aadimos un constructor a la clase RequestThread para poder inicializar las variables anteriores. Como siempre, lo primero que hacemos es llamar al constructor del padre (constructor de la clase Thread de Java): public RequestThread(String latitude, String longitude, Handler myHandler) { super(); this.latitude = latitude; this.longitude = longitude; this.myHandler = myHandler; } 4. Lo siguiente es aadir el mtodo ms importante, el mtodo run() (pblico, sin retorno y con uso del @Override porque estamos sustituyendo un mtodo de la clase padre). ste es el mtodo del hilo que se ejecuta en segundo plano, ya que el resto del cdigo, incluyendo el constructor del RequestThread, funcionar sobre el mismo hilo, es decir, sobre el de la interfaz grfica. Copiar el siguiente cdigo al mtodo run():


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 9 de 14

try {

// obtenemos una conexin DefaultHttpClient httpClient = new DefaultHttpClient(); String url = "http://maps.googleapis.com/maps/api/geocode/json?latlng=" + latitude + "," + longitude + "&sensor=false"; // creamos una peticin de tipo GET (parmetros en la URL) HttpGet request = new HttpGet(); request.setURI(new URI(url)); // ejecutamos la peticin HttpResponse response = httpClient.execute(request); // convertimos la respuesta en string String responseString = EntityUtils.toString(response.getEntity()); // escribimos el resultado Message msg = new Message(); // de qu trata el mensaje msg.what = 0; // aadir datos Bundle data = new Bundle(); data.putString(RequestActivity.__RESPONSE_KEY__, responseString); // colocamos los datos msg.setData(data); // enviamos el mensaje myHandler.sendMessage(msg); // cerramos la conexin httpClient.getConnectionManager().shutdown(); } catch (Exception e) { e.printStackTrace(); // mensaje vaco (sin datos) myHandler.sendEmptyMessage(1); }

Revisemos el cdigo con calma. Lo primero es ver que se trata del mismo bloque try/catch que nos detena la ejecucin de la aplicacin en el mtodo makeRequest() de la RequestActivity. Los cambios vienen a partir de que obtenemos la respuesta como String, pero antes miremos la nueva lnea del bloque catch. En ella, enviamos un mensaje al Handler, un mensaje vaco (sin datos), en el que el nico parmetro que hay asigna un valor al campo what del Message. Este campo what se utiliza para identificar qu se est enviando con el
Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 10 de 14

mensaje; cuando se quieren enviar distintos mensajes sin enviar datos pesados, se envan mensajes vacos con distintos valores para el campo what. El receptor, que pondremos en la clase RequestActivity, preguntar al mensaje cul es el valor de su campo what, y as sabr qu significa la recepcin de ese mensaje. Si miramos el final del bloque try, veremos que creamos una nueva variable de tipo Message, que asignamos el valor del campo what a cero (en el catch le asignamos 1), que creamos un Bundle, y que en el Bundle aadimos el String que hemos recibido (como clave utilizamos un campo que aadiremos ahora a la clase RequestFragment). Por ltimo, colocamos el Bundle en el mensaje, y lo enviamos, sin olvidarnos de cerrar la conexin HTTP. 5. Como acabamos de mencionar, debemos aadir una variable pblica, esttica, final (final) de tipo String con nombre __RESPONSE_KEY__ a la cabecera de la clase RequestFragment. Adems, debemos ir al mtodo makeRequest(), y eliminar todas las lneas que siguen a aquellas en las que desactivamos los EditText y el requestButton. A continuacin, creamos un RequestThread a cuyo constructor le pasamos el texto de los EditText (latitudeET, longitudeET) y una variable (myHandler) que crearemos en el ltimo paso. Para terminar, llamamos al mtodo start(), sin parmetros, del RequestThread que acabamos de crear. 6. Tras el mtodo makeRequest(), debemos aadir el siguiente cdigo:
Handler myHandler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 0) { // response resultET.setText((String)msg.getData().get(Request Activity.__RESPONSE_KEY__)); } if (msg.what == 1) { resultET.setText(getString(R.string.error)); } // activamos todo latitudeET.setEnabled(true); longitudeET.setEnabled(true); requestButton.setEnabled(true); } };


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 11 de 14

7. Como podis ver, el mtodo es muy sencillo. Si el what es cero, recogemos el String y se lo asignamos al EditText de resultado; si es 1, es que ocurri una excepcin, luego debemos mostrar un mensaje de error (dejamos este String a los alumnos). En cualquier caso, la ejecucin del hilo termina, luego podemos volver a activar los EditText y el botn de peticin. Como ltima nota en lo que respecta al cdigo, os daris cuenta de que existe un warning en lo referente al Handler; esto es porque este elemento debera instanciarse unido a un contexto como puede ser una Activity, y para no complicar el cdigo ni introducir demasiados elementos nuevos, hemos simplificado el ejercicio.


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 12 de 14

D. Cuestiones y Conclusiones Finales


1. Por qu utilizamos el mtodo start() en vez de llamar al mtodo run() directamente desde el makeRequest() en RequestActivity? Probarlo. Por qu se comporta de esta forma? 2. Por qu utilizamos un Handler? Por qu no podemos realizar lo que hace el Handler directamente desde el mtodo run() de la clase RequestThread? Qu ocurre si lo hacemos? 3. Por qu tenemos tanto miedo de que la llamada al Web Service detenga nuestra aplicacin? Qu consecuencias tiene esto para el usuario? Vayamos por partes. Lo primero es que s, son muchos conceptos para asimilar en un nico ejercicio, pero sta, en realidad, es la forma ms simple y real de encontrarse con el problema de bloquear (o detener) el hilo de la interfaz grfica. Este problema lo vivimos constantemente con las aplicaciones de escritorio que utilizamos, sin embargo, en un smartphone la situacin resulta ser mucho ms estresante, ya que el usuario no tiene ningn sitio al que correr si nuestra aplicacin satura al sistema operativo (dependiendo del telfono, es posible volverlo tan lento que el propio proceso HOME tenga que cerrarse), al contrario que en Windows y en Mac, donde podemos cerrar las aplicaciones y volver a abrirlas si nos hace falta. Esta estrategia de Thread(s) y Handler(s) no es exclusiva de Android, y puede utilizarse perfectamente en Java. Sin embargo, cabe mencionar que no es la nica forma de realizar esta gestin en Android; hay dos tipos ms que esperamos ver en un futuro curso Avanzado de Android.

Lo siguiente es reforzar la importancia de los Message. Cuando se enva un mensaje a un Handler, ste es colocado al final de una cola para ser procesado por el mtodo handleMessage() que nosotros sustituimos en nuestro Handler. Esto ocurre de forma asncrona, provocando que el hilo en el que se encuentra el handler ejecute un handleMessage() con el mensaje correspondiente. Esto nos permite utilizar esta estrategia con mucha flexibilidad; podemos crear tantos eventos (valores del argumento what) como queramos, permitindonos conocer en cualquier momento en qu estado se encuentra nuestro hilo en segundo plano. Naturalmente, la utilidad de esta estrategia se ve mejor cuanto ms complicada es la interaccin entre el hilo en segundo plano y el hilo de la interfaz grfica. Podra incluso utilizarse un nico handler para recibir eventos de mltiples hilos, pues todos van a la misma cola. Ahora bien, las acciones que llevemos a cabo en el handler no pueden ser lentas (es decir, no pueden detener el hilo de la interfaz grfica), o estaremos de vuelta en el mismo punto del que partimos.

Ahora vienen los hilos. El hilo de tipo RequestThread que creamos desde la RequestActivity, en realidad, se ejecuta desde el mismo hilo que lo cre (es decir, el de Desarrollo de Aplicaciones Mviles en Android Pgina 13 de 14 Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues
Autores: Jorge Carballo Franquis David D. Harjani Harjani

la interfaz grfica) Si nosotros llamsemos al mtodo run() directamente, sera como si el hilo no existiese, porque sera como si ejecutsemos un mtodo ms de un objeto cualquiera; es decir, se ejecutara desde el hilo de la interfaz, luego el esfuerzo que hemos hecho habr sido en vano. En realidad, las clases Thread y similares (Runnable) lo que hacen es proporcionarnos una forma fcil de ejecutar cdigo en otro hilo sin que nosotros tengamos que realizar ninguna gestin. Por eso la utilidad de la clase Thread radica en que utilicemos el mtodo start(), porque se encarga de crear un nuevo hilo y de mantenerlo en funcionamiento ejecutando cdigo, y el cdigo que ejecuta es, por supuesto, el del mtodo run(). Nota: La clase Thread proporciona ms mtodos para controlar la ejecucin del hilo que ejecuta el mtodo run(). Se han obviado para simplificar el texto y transmitir las ideas principales. Sin embargo, ejecutar cdigo en segundo plano es un poco ms complicado de lo que hemos dicho hasta ahora. Si nosotros intentramos llamar a las Views desde el mtodo run() del hilo, obtendramos una excepcin en tiempo de ejecucin, una excepcin medianamente grave. Esto se debe a que las Views no pertenecen al hilo que est ejecutando el cdigo (RequestThread), sino a otro (hilo de interfaz de RequestActivity). Se trata de una convencin en frameworks de programacin con interfaz grfica (.NET, Cocoa, Cocoa Touch, y por supuesto Android) que los elementos de la interfaz slo puedan ser llamados desde el propio hilo que los cre. Esto da lugar a un concepto muy utilizado, el de thread safety. Cuando un elemento es thread safe, significa que puede ser utilizado (llamado) desde cualquier hilo. En el caso de Android los elementos de la interfaz (Views) no son thread safe. Es aqu donde el handler comienza a tener sentido; los mtodos que permiten enviarle mensajes al handler son thread safe, y como ya dijimos, el mtodo que procesa los mensajes se ejecuta desde el hilo que cre el handler (en nuestro caso, el de la interfaz de RequestActivity). As de cmo hemos decidido solucionar el problema de comunicarnos desde el cdigo ejecutando en segundo plano con la interfaz en este ejercicio, pero como ya hemos dicho, hay ms (y mejores) soluciones. Existen otros mtodos para realizar comunicaciones con un servidor; Android, al implementar un subconjunto de Java 6, suele ser muy flexible importando libreras hechas para Java (archivos .jar), lo que nos permite utilizar otra librera con la que nos sintamos ms cmodos o incluso aportar algo que no permita la librera que incluye Android, como por ejemplo, el envo de mltiples archivos mediante un POST (recomendamos utilizar la librera Apache Commons para esto). Sin embargo, llegados a cierto punto, simplemente conocer cmo funciona la plataforma o librera con la que estemos trabajando no nos llevar ms lejos, sino que ser nuestro ingenio el que tendr que resolver los problemas que no os han sido resueltos hasta ahora.


Desarrollo de Aplicaciones Mviles en Android Ejercicio Avanzado B: Web Services y Ejecucin en Segundo plano Hashtag: #droidissues Autores: Jorge Carballo Franquis David D. Harjani Harjani

Pgina 14 de 14

También podría gustarte