Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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?
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.
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
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