Está en la página 1de 27

Aplicacin Android + Servicio PHP

by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

Aplicacin Android + Servicio PHP

Tutorial para crear una aplicacin en Android que consulta datos de una pgina web en PHP (como un webservice), la cual a su vez realiza consultas a una base de datos MySQL. Este tutorial representa un buen punto de partida para los iniciados en Android que quieren aprender a hacer una aplicacin de las que se usan en el mundo real, sin complicarse en el diseo ni en cuestiones monetarias. La aplicacin que os voy a ensear es una consulta sencilla a una base de datos de pelculas que podemos tener todos en casa y ahora en nuestro mvil.

Descripcin Vamos a desarrollar una aplicacin para Android que busca pelculas en nuestra base de datos segn una parte del ttulo que el usuario quiera poner o todas las que hay si el usuario no especifica ningn filtro. Dicha aplicacin ser la interfaz grfica para que el usuario vea el listado de pelculas. Su funcin es capturar los parmetros de bsqueda que quiera especificar el usuario; en nuestro caso solo habr 2: una parte del ttulo y el nmero mximo de resultados devueltos que desea ver. Luego enviar estos datos o filtros de bsqueda a un webservice, que en nuestro caso no es ms que una pgina PHP sin ms complicaciones. La pgina enviar la consulta correspondiente a la base de datos con los parmetros recogidos por la aplicacin para filtrar la bsqueda; y por ltimo, transformar dichos datos en un archivo descargable para la aplicacin Android, la cual leer estos datos y presentar en un listado las pelculas resultantes. Resumiendo, los elementos ms importantes de los que se compone este tutorial son los siguientes: Aplicacin Android: Aplicacin desde la cual obtendremos un listado de pelculas. Base de Datos: Una base de datos en MySQL muy sencilla con una tabla pelculas. Transferencia de datos: Una pgina web PHP que recibir peticiones de la aplicacin Android y le devolver datos para presentar el listado. Tcnicas Utilizadas Lo ms laborioso para un iniciado pueden ser estos cuatro puntos, aunque no son nada complicados, ya lo vers. Construir una pgina PHP que reciba 2 parmetros y conecte con la base de datos MySQL pasndole una sentencia con dichos parmetros. Transferir los datos recuperados de la base de datos a la aplicacin Android por GET HTTP; para ello los vamos a serializar en un archivo binario y la pgina PHP no mostrar nada si no que descargar dicho archivo. La serializacin y deserializacin de los datos binarios del archivo que transfiere la pgina PHP a la aplicacin Android la realizaremos utilizando Google protocol buffers. Mostrar el listado de resultados en otra pantalla Android distinta a la que ejecut la consulta. Qu Necesito? Servidor Web que compile PHP: Apache o IIS Servidor de Bases de Datos MySQL: pgina de descarga Entorno de desarrollo Eclipse con Android ADT. Si vas a la pgina oficial de Android Developers puedes

pgina 1 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

descargar las dos cosas en un mismo paquete sin necesidad de instalacin. Compilador prtobuf: archivo protoc.exe Utilidad de generacin de clases PHP para protobuf: pb4php Librera precompilada Google protobuf Java (archivo .jar) para deserializar datos en Android. Debemos utilizar la librera JAR de la misma versin que el compilador protoc.exe. Si por ejemplo, descargamos el compilador 2.4.0 necesitamos el JAR 2.4.0, de lo contrario, si utilizamos versiones diferentes no funcionar.

Lo que yo he utilizado

Servidor web: IIS con PHP 5.4.6 Servidor bbdd: MySQL 5.5.20 x86 Eclipse 4.2.1 Android ADT plugin para Eclipse r21.0.0 Compilador protoc 2.4.1 x86 pb4php 0.25
Cmo lo he configurado

1. Descargu el archivo .zip de la seccin VC9 x86 Thread Safe de la pgina oficial de PHP y lo descomprim en C:\PHP\. Luego configur mi IIS como en el artculo de mi blog. 2. Descargu el archivo mysql-5.5.20-win32.msi de la pgina oficial de MySQL y lo instal con las opciones predeterminadas en mi mquina local (127.0.0.1) 3. Descargu el paquete completo de desarrollo Android de la pgina oficial de Android SDK, luego descomprim su contenido en C:\adt-bundle-windows\ 4. Descargu el archivo protoc-2.4.1-win32.zip de la pgina oficial de Google y lo descomprim en C:\Archivos de programa\protoc.exe 5. Descargu el archivo protocolbuf_025.zip de la pgina oficial y descomprim los subdirectorios message y parser completos bajo mi carpeta C:\inetpub\wwwroot\php\peliculas\lib\pb4php\, adems de extraer el archivo example\protoc.php del zip al mismo sitio. 6. Descargu el archivo protobuf-java-2.4.1.jar de aqu y lo he colocado en la carpeta libs del proyecto Eclipse para la aplicacin Android. (Llegaremos a este punto ms adelante) Base De Datos Slamente vamos a necesitar una tabla llamada peliculas con id y ttulo. A continuacin el script para crear la base de datos y la tabla con algunas filas de ejemplo: CREATE DATABASE IF NOT EXISTS peliculas; USE peliculas; DROP TABLE IF EXISTS `pelicula`; CREATE TABLE `pelicula` ( `PEL_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `PEL_titulo` varchar(64) COLLATE utf8_spanish_ci NOT NULL, PRIMARY KEY (`PEL_id`), KEY `ix_titulo` (`PEL_titulo`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci; INSERT INTO `pelicula` (`PEL_id`,`PEL_titulo`) VALUES (1,'Rocky'), (2,'El Seor de los anillos'), (3,'Terminator 2'),

pgina 2 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

(4,'Esta casa es una ruina'), (5,'Apolo XIII'), (6,'Alien'), (7,'Parque Jursico'), (8,'Parque Jursico 2'), (9,'Misin Imposible'), (10,'Torrente');

Una vez que tenemos la base de datos funcionando vamos a crear la pgina web que conecta a dicha base de datos. top

Webservice PHP El webservice es una pgina normal PHP que no muestra nada, en vez de eso, devuelve los resultados en forma de un archivo descargable. Crea una pgina web vaca llamada index.php en tu servidor, yo la he creado en C:\inetpub\wwwroot\php\peliculas\index.php Antes de soltar todo el cdigo fuente de la pgina PHP, me gustara explicar algunos conceptos que he considerado Este sera un fragmento de PHP para capturar los parmetros de la pgina if (isset($_GET['t'])) { $pTitle = $_GET['t']; // ttulo a consultar } if (isset($_GET['r'])) { $pMaxResults = $_GET['r']; // nm. mx. de resultados a devolver }

Con lo cual llamaramos a la pgina as: Para obtener todos los resultados: http://localhost/php/peliculas/index.php Para obtener 3 resultados: http://localhost/php/peliculas/index.php?r=3 Para buscar las que contengan parque jursico: http://localhost/php/peliculas/index.php?t=parque%20jursico Para buscar las 5 primeras que contengan parque: http://localhost/php/peliculas/index.php?t=parque&r=5 Observa que la parte textual del ttulo debe estar codificada, ya que si ponemos t=parque jursico separados por un espacio en blanco, el servidor pensara que estamos pasando el parmetro t=parque y luego hay otro parmetro suelto llamado jursico sin valor. No te preocupes, hay una funcin que hace esto. Por ahora, slo es un detalle que debes tener en cuenta.

pgina 3 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

Con este fragmento de cdigo conectamos a una base de datos y recogemos los datos. // Crea la conexin a la base de datos e intenta conectar $con = new mysqli('127.0.0.1', 'root', 'password', 'peliculas'); if ($con->connect_errno) { echo 'Connect failed: ', $con->connect_error; exit(); } $con->set_charset('utf8'); // Forma la consulta SQL $sql = 'SELECT PEL_id, PEL_titulo FROM `pelicula` '; // Si el parmetro ttulo contiene algo, inserta la condicin if (isset($pTitle)) { $pTitle = trim($pTitle); if (0 != strlen($pTitle)) { $sql .= 'WHERE PEL_titulo LIKE CONCAT(?, \'%\') '; } } // Indica el orden de los resultados $sql .= 'ORDER BY PEL_titulo'; // Lmite de resultados, si el parmetro ha sido especificado if (isset($pMaxResults)) { $sql .= ' LIMIT '.$pMaxResults; } // Inicializa la sentencia antes de ejecutarla $stmt = $con->stmt_init(); if ($stmt->prepare($sql)) { // Inserta el valor del parmetro para el ttulo en la sentencia // (en caso de que lo hubiera) if (isset($pTitle)) { $stmt->bind_param('s', $pTitle); } // Ejecuta la sentencia SQL $stmt->execute(); // Los campos devueltos por la sentencia se almacenarn // en las variables que indicamos a continuacin $stmt->bind_result($col_id, $col_titulo); // Recorre cada fila devuelta e imprime los campos obtenidos while($stmt->fetch()) { echo $col_id.' - '.$col_titulo.'<br/>'; } // Cierra elementos abiertos y libera memoria $stmt->close(); unset($stmt); }

pgina 4 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

// Cierra la conexin a la base de datos y libera variables $con->close(); unset($con); unset($sql);

Ahora falta la parte ms difcil: generar un archivo binario con los resultados obtenidos, en vez de imprimirlos. Aqu es donde interviene el mtodo de serializacin de datos Google protocol buffers. Te puedes familiarizar con este mtodo leyendo mis artculos: Serializar en Java Protocol Buffers en Java Protocol Buffers en C#

Serializar los resultados a un archivo binario y transferirlo


El mtodo usado por Google es muy prctico porque se transfieren los datos mnimos de informacin por lo que ocupa poco espacio y es muy rpido. Ahora bien, si habis ledo algo sobre este mtodo sabris que consiste en crear un mensaje (archivo .proto) y pasarlo por el compilador protobuf para obtener el archivo de cdigo fuente con el que podremos trabajar (en nuestro caso, un archivo de clase .php). Queremos una clase llamada Pelcula en PHP. Pues entonces creamos un archivo ANSI (no UTF-8!) como este: message Pelicula { required int32 id = 1; required string titulo = 2; } message ListaPeliculas { repeated Pelicula pelicula = 1; }

Y lo guardamos en C:\inetpub\wwwroot\php\peliculas\lib\Peliculas.proto. Con esto generaremos dos clases en PHP: - clase Pelicula: Para cada elemento individual. - clase ListaPeliculas: Para manejar la lista de resultados fcilmente con un objeto de esta clase. En la pgina oficial encontrars informacin sobre cmo especificar tus estructuras de datos en archivos .proto. Como el compilador de Google protoc.exe no es capaz de convertir el archivo .proto que acabamos de crear en cdigo fuente PHP, echaremos mano de la utilidad pb4php. Primero vamos a editar el archivo C:\inetpub\wwwroot\php\peliculas\lib\pb4php\protoc.php para que tenga el siguiente contenido: <?php require_once('parser/pb_parser.php'); $parser = new PBParser();

pgina 5 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

$parser->parse('../Peliculas.proto'); echo 'File parsing done!'; ?>

Y abrimos la siguiente direccin en nuestro navegador: http://localhost/php/peliculas/lib/pb4php/protoc.php Verifica si ha creado el archivo C:\inetpub\wwwroot\php\peliculas\lib\pb4php\pb_proto_Pelicula.php, en caso contrario, es posible que no tengas permisos de escritura en dicha carpeta. Slo tienes que drselos haciendo click derecho en la carpeta y marcar la casilla de Modificar en los permisos del grupo de usuarios IIS_IUSRS. Luego vuelve a llamar a protoc.php Si ya tienes el archivo pb_proto_Pelicula.php creado, muvelo a la carpeta C:\inetpub\wwwroot\php\peliculas\lib. Este archivo, dentro contiene la clase Pelicula y la clase ListaPeliculas con las que vamos a terminar de hacer nuestro index.php. Finalmente <?php require_once('lib/pb4php/message/pb_message.php'); require_once('lib/pb_proto_Pelicula.php'); ob_start(); // Crea y abre la conexin con la bbdd $con = new mysqli('127.0.0.1', 'root', 'password', 'peliculas'); if ($con->connect_errno) { echo 'Connect failed: ', $con->connect_error; exit(); } $con->set_charset('utf8'); // Recupera los parmetros de esta pgina if (isset($_GET['t'])) { $pTitle = $_GET['t']; // parte del ttulo a consultar } if (isset($_GET['r'])) { $pMaxResults = $_GET['r']; // nm. mx. de resultados a devolver } // Empieza a crear la consulta SQL $sql = 'SELECT PEL_id, PEL_titulo FROM `pelicula` '; // Aade filtro para buscar parte del ttulo si se especific if (isset($pTitle)) { $pTitle = trim($pTitle); if (0 != strlen($pTitle)) { $sql .= 'WHERE PEL_titulo LIKE CONCAT(?, \'%\') '; } }

pgina 6 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

$sql .= 'ORDER BY PEL_titulo, PEL_id'; // Aade lmite de resultados a la consulta si se especific if (isset($pMaxResults)) { $sql .= ' LIMIT '.$pMaxResults; } $stmt = $con->stmt_init(); if ($stmt->prepare($sql)) { // Asigna valor al parmetro 'ttulo' de la consulta SQL if (isset($pTitle)) { $stmt->bind_param('s', $pTitle); } // Ejecuta la consulta SQL $stmt->execute(); // Los campos devueltos del resultado de cada fila, se // introducirn en las siguientes variables: $stmt->bind_result($PEL_id, $PEL_titulo); // Crea una nueva lista de peliculas donde almacenar // el resultado obtenido de la consulta en la bbdd. $lista_resultado = new ListaPeliculas(); while($stmt->fetch()) { // Crea un nuevo elemento en la lista y le asigna sus campos $m = $lista_resultado->add_pelicula(); $m->set_id($PEL_id); $m->set_titulo($PEL_titulo); } // Cierra elementos y libera memoria $stmt->close(); unset($row); unset($result); unset($stmt); // Convierte en binario todo el resultado (Serializacin) $bytes = $lista_resultado->SerializeToString(); } // Cierra la conexin SQL y libera las variables $con->close(); unset($con); unset($sql); // Prepara la salida de datos de esta pgina $size = strlen($bytes); header('Content-Length: '.$size); header('Content-type: application/octet-stream'); header('Content-Disposition: attachment; filename="datos.bin"');

pgina 7 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

header('Content-Transfer-Encoding: binary'); ob_flush(); ob_clean(); // Escribe los datos binarios en la salida de esta pgina echo $bytes; ob_end_flush(); exit(); ?>

Si pruebas abrir la pgina http://localhost/php/peliculas/index.php?r=5 se descargar el fichero datos.bin que ha generado con los resultados recuperados, esto es, las 5 primeras pelculas de tu base de datos, en formato binario.

Hasta ahora lo que hemos hecho ha sido generar los datos que va a consumir nuestra aplicacin de Android. Ahora continuaremos creando dicha aplicacin y consumiendo estos datos para mostrarlos al usuario en una lista.

top

Aplicacin Android

Primeros pasos en Eclipse


El entorno de desarrollo Eclipse no necesita instalacin, podemos iniciarlo haciendo doble click directamente en eclipse.exe. La primera vez que lo inicies te preguntar dnde quieres colocar la carpeta workspace que contendr tus proyectos.

pgina 8 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

Primero de todo debes asegurarte de que tu sistema tiene Java instalado. Puedes descargarte la ltima verisn de aqu o actualizar la que ya tienes (desinstalando primero la versin vieja). Luego puedes optar por una de las dos opciones siguientes: 1. Descargar Eclipse, el SDK de Android para Windows y el plugin de Android para Eclipse (ADT), e instalarlo todo individualmente. 2. Descargar el paquete de desarrollo Eclipse preparado de la pgina oficial de desarrollo Android aqu, que lo trae todo junto y configurado. Es preferible la primera opcin, pero s que muchos de vosotros escogeris la segunda por la facilidad que aporta bajarse un zip, descomprimir y listo para empezar a programar. De todas formas, si eliges la primera opcin, sigue estos pasos: 1. Descarga el Eclipse Classic de la pgina oficial. 2. Descomprime el paquete en una carpeta donde tengas permisos de escritura. Si no ests seguro extrelo a C:\Eclipse. 3. Hazte un acceso directo donde quieras al ejecutable, brelo e inicia los primeros pasos para especificar la carpeta workspace. 4. Descarga el instalador de Windows Android SDK de aqu, en la seccin Download for other platforms > SDK Tools only. Luego instlalo. 5. Ahora ve al Eclipse > Help > Install new software. 6. En la ventana que aparece pulsa el botn Add y en el dilogo escribe Name: ADT Plugin, Location: https://dl-ssl.google.com/android/eclipse/. Guarda y cuando cargue selecciona Developer Tools y ya contina la instalacin aceptando las licencias y tal. 7. Una vez que tenemos instalado el plugin, reiniciamos Eclipse y vamos al men Window. Ya vers

pgina 9 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

opciones nuevas para Android. Entra en Preferences > Android y escribe en SDK location la ruta a la carpeta donde instalaste el SDK de Windows. Aplica los cambios. 8. Abre el men Window > Android SDK Manager, revisa que tienes la ltima versin de todo y opcionalmente puedes instalar las Google APIs. 9. Luego ve a Window > AVD Manager y agrega un dispositivo virtual Android con las opciones por defecto. Aqu puedes crear telfonos mviles, tabletas, etc. 10. Si quieres probar el dispositivo Android que has creado pulsa el botn Start del AVD Manager. Si elegiste la segunda opcin (bajarse el Eclipse preparado con todo), slo debes realizar los pasos anteriores a partir del 8 en adelante. var $jq = jQuery.noConflict(); $jq(document).ready(function() { $jq('#EclipseInstallADT').coinslider({ width: 300, height: 260, spw: 7, sph: 5, delay: 5000, sDelay: 30, opacity: 0.7, titleSpeed: 1500, effect: 'fade', navigation: true, links : true, stickynav: false, hoverPause: true }); });

pgina 10 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

pgina 11 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

pgina 12 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

La aplicacin Android
Crea un nuevo proyecto Android llamado Peliculas con un icono que te guste utilizando el asistente de Eclipse. Crear todo un rbol de directorios y la pantalla inicial de la aplicacin. var $jq = jQuery.noConflict(); $jq(document).ready(function() { $jq('#EclipseNewProject').coinslider({ width: 300, height: 275, spw: 7, sph: 5, delay: 5000, sDelay: 30, opacity: 0.7, titleSpeed: 1500, effect: 'fade', navigation: true, links : true, stickynav: false, hoverPause: true }); });

pgina 13 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

pgina 14 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

pgina 15 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

pgina 16 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

En la carpeta libs del proyecto, pega la librera protobuf-java-2.4.1.jar. Abre el archivo AndroidManifest.xml y en la pestaa Permissions aade INTERNET para que la aplicacin pueda acceder a Internet, puesto que necesitaremos que llame a nuestra pgina PHP. Ahora crea una clase nueva que extienda la super clase Application, bajo la carpeta src/peliculas, as: package peliculas; import android.app.Application; public class Peliculas extends Application { public ListaPeliculas lPeliculas; public Peliculas() { } }

Aqu hemos puesto una variable global llamada lPeliculas para poder compartir los datos entre pantallas. La clase de esta variable: ListaPeliculas todava no la hemos creado, pero tampoco la podemos crear manualmente. El compilador de protobuf protoc.exe ser el que la cree automticamente a partir del archivo .proto que creamos anteriormente. Para ello, dentro de la carpeta src del proyecto crea una subcarpeta llamada proto. En ella, pega el archivo Pelicula.proto. Luego, desde la lnea de comandos, bajo este mismo directorio ejecuta el siguiente comando todo seguido en una lnea: "C:\Program Files (x86)\protoc.exe" --java_out=C:\users\samuel\workspace\peliculas\src\

pgina 17 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

--proto_path=C:\users\samuel\workspace\peliculas\src\proto C:\users\samuel\workspace\peliculas\src\proto\Peliculas.proto

Modifica las rutas a los archivos segn tu instalacin y tu sistema. El compilador de protocol buffers habr generado nuestras clases java a partir del archivo .proto. Coloca el archivo resultante bajo la carpeta src\peliculas. Ahora ya tienes las clases Pelicula y ListaPeliculas en Java para poder trabajar con ellas. Ahora vamos a crear la pantalla inicial El layout debe ir en res\layout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <TextView android:id="@+id/tvSearchLabel" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/txtSearchLabel"></TextView> <EditText android:id="@+id/txtSearchTitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:hint="@string/hntSearchTitle" android:layout_marginTop="10dip" > <requestFocus /> </EditText> <EditText android:id="@+id/txtSearchLimit" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" android:inputType="number" android:hint="@string/hntSearchLimit" /> <Button android:id="@+id/btnSearch" android:layout_width="match_parent" android:layout_height="wrap_content" android:onClick="sendQuery" android:text="@string/btnSearchLabel" /> </LinearLayout>

pgina 18 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

Para que quede algo as (modifica los textos a tu gusto en el archivo res\values\strings.xml):

Esta pantalla va a llevar a cabo una tarea asncrona (descargar un archivo del webservice) que no sabemos cunto va a tardar, por eso Android tiene la super clase AsyncTask<P1, P2, P3>. Al implementar una clase de esta super clase, Android abre otro hilo de ejecucin para que este tipo de tareas tarden lo que necesiten sin paralizar el hilo de ejecucin principal, porque si la tarea queda esperando a que el servidor web le responda, nuestra interfaz grfica se quedara congelada mientras tanto, dando la sensacin de que el programa se ha colgado. Necesitamos crear una clase que derive de AsyncTask para realizar el proceso de llamar al webservice, recoger los datos devueltos y deserializarlos. Todo este proceso es asncrono y no debe bloquear el programa. Al pulsar el botn Buscar ejecutaremos esta nueva clase. package peliculas; import import import import import java.io.BufferedInputStream; java.io.ByteArrayOutputStream; java.io.InputStream; java.net.HttpURLConnection; java.net.URL;

pgina 19 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

import import import import

android.content.Context; android.os.AsyncTask; android.util.Log; peliculas.ListaPeliculas;

public class QueryMovies extends AsyncTask<String, Void, ListaPeliculas> { private Context context; public QueryMovies(Context pContext) { this.context = pContext; } @Override protected ListaPeliculas doInBackground(String... arg0) { if (arg0.length != 0) { return getMovies(arg0[0]); } else { return null; } } protected ListaPeliculas getMovies(String arg0){ // Resultado a devolver ListaPeliculas res = ListaPeliculas.getDefaultInstance(); HttpURLConnection httpcon; try { // Conecta con la pgina web cuya direccin tenemos en arg0 URL url = new URL(arg0); httpcon = (HttpURLConnection)url.openConnection(); httpcon.connect(); // En caso de respuesta afirmativa del servidor. if (HttpURLConnection.HTTP_OK == httpcon.getResponseCode()) { // Leemos la informacin que llega por respuesta y la almacenamos // en una variable llamada buffer, de tipo byte[]. InputStream ist = httpcon.getInputStream(); BufferedInputStream b_input = new BufferedInputStream(ist); ByteArrayOutputStream b_output = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int read = b_input.read(buffer, 0, 4096); while (-1 != read) { b_output.write(buffer, 0, read); read = b_input.read(buffer, 0, 4096); } // Dejamos en buffer los datos resultantes obtenidos, // es decir, el listado de resultados en formato binario. buffer = b_output.toByteArray();

pgina 20 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

// Cierra streams y conexin b_output.close(); b_input.close(); ist.close(); httpcon.disconnect(); // Slo para PHP en servidores IIS // Nos debemos deshacer de los 3 primeros caracteres de la respuesta /*if (buffer.length > 2) { System.arraycopy(buffer, 3, buffer, 0, buffer.length - 3); }*/ // Deserializacin con PROTOCOL BUFFERS res = ListaPeliculas.parseFrom(buffer); } else { httpcon.disconnect(); Log.e("QueryMovies()", httpcon.getResponseMessage()); } } catch(Exception e) { e.printStackTrace(); } return res; } @Override protected void onPostExecute(ListaPeliculas result) { super.onPostExecute(result); ((IMyActivity)this.context).TaskCallback(result); } }

doInBackground es lo que se va a ejecutar al ejecutar esta clase. Y cuando termine, se ejecutar automticamente (sin que tengamos que hacer nada) onPostExecute. La manera de proceder de la clase QueryMovies es sencilla: crearemos la clase desde el contexto de la pantalla inicial (de ah el constructor), luego le pasaremos por parmetro la URL del webservice ya formada para que devuelva los resultados de la consulta en formato binario (serializado), despus, en un bucle leer bloques de bytes hasta haber ledo todo lo que devuelve el webservice (de 4KB en 4KB), luego deserializa los bytes recogidos para obtener el listado de pelculas correspondiente y por ltimo onPostExecute llama de vuelta a la funcin TaskCallback de la pantalla que inici esta tarea asncrona (nuestra pantalla inicial de bsqueda), devolvindole por parmetro la lista de pelculas resultante. En la lnea 93 la pantalla que llam a esta clase (MainActivity) est en this.context, pero adems vers que le he puesto delante el tipo de datos IMyActivity. Explico el por qu: Cualquier pantalla de nuestra aplicacin podra crear una clase QueryMovies por lo que en la lnea 93 this.context podra ser cualquier clase. He aqu un prequeo problema, que no tenemos la funcin TaskCallback() en cualquier clase. Nosotros sabemos que est en MainActivity pero no sabemos si est en

pgina 21 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

alguna otra. Para solucionar este inconveniente obligamos a la clase MainActivity (y todas aquellas que vayan a utilizar QueryMovies) a tener la funcin TaskCallback() implementada mediante el uso de una Interface. Haremos la inteface IMyActivity en src\peliculas package peliculas; public interface IMyActivity { public void TaskCallback(ListaPeliculas result); }

Y las pantallas que utilicen QueryMovies la deben implementar siempre. package peliculas; import java.net.URLEncoder; import import import import import import import import import android.app.Activity; android.content.Intent; android.os.Bundle; android.util.Log; android.view.Menu; android.view.MenuItem; android.view.View; android.widget.EditText; android.widget.Toast; {

public class MainActivity extends Activity implements IMyActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Establece el nmero mx. de resultados por defecto EditText et = (EditText)findViewById(R.id.txtSearchLimit); et.setText("25"); } public void sendQuery(View v) { QueryMovies q = new QueryMovies(this); StringBuilder sb = new StringBuilder(); sb.append("http://127.0.0.1/peliculas/index.php");

try { EditText et = (EditText)findViewById(R.id.txtSearchTitle); String txtTitle = et.getText().toString(); txtTitle = txtTitle.trim(); et = (EditText)findViewById(R.id.txtSearchLimit);

pgina 22 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

String txtLimit = et.getText().toString(); if (!txtTitle.isEmpty() || !txtLimit.isEmpty()) { sb.append("?"); if (!txtTitle.isEmpty()) { sb.append("t="); sb.append(URLEncoder.encode(txtTitle, "utf-8")); if(!txtLimit.isEmpty()) { sb.append("&r="); sb.append(txtLimit); } } else if(!txtLimit.isEmpty()) { sb.append("r="); sb.append(txtLimit); } } q.execute(sb.toString()); } catch(Exception e) { e.printStackTrace(); } } public void TaskCallback(ListaPeliculas result) { if (null != result) { if (0 != result.getPeliculaCount()) { // Guarda en la variable global de la aplicacin el listado resultan te ((Peliculas)getApplicationContext()).lPeliculas = result; // Inicia una nueva pantalla donde mostrar el listado al usuario Intent i = new Intent(this, ResultsActivity.class); startActivity(i); } else { Toast.makeText(getApplicationContext(), "La bsqueda no devolvi nin gn resultado.", Toast.LENGTH_LONG).show(); } } else { Toast.makeText(getApplicationContext(), "No fue posible recuperar result ados.", Toast.LENGTH_LONG).show(); } } }

- La funcin sendQuery es la accin que se lleva a cabo al pulsar el botn Buscar. Segn los campos

pgina 23 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

introducidos, forma la URL que debe llamar a nuestro webservice PHP. En la lnea 59 ejecuta la tarea asncrona que implementamos en la clase QueryMovies y el cdigo sigue su curso, ya que la tarea asncrona se est ejecutando de fondo, en otro hilo de ejecucin. Al terminar este otro hilo, la siguiente funcin ser ejecutada.

- La funcin TaskCallback es ejecutada en cuanto la tarea asncrona termine y smplemente comprueba que si
vienen resultados hay que abrir una nueva pantalla para mostrarlos. top La pantalla de resultados slamente contiene el control para el listado: un listview, cuyo layout ser: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".ResultsActivity" > <ListView android:id="@+id/lvListado" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout>

Cada elemento del listado aparecer en pantalla cmo lo configuremos en su propio layout tambin. A continuacin pongo el layout de un elemento del listado: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/listado_item_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp" android:ellipsize="end" android:paddingTop="2dip" android:paddingBottom="2dip"/> </LinearLayout>

Slo hay un TextView para poner el ttulo de la pelcula. Suficiente para nuestras necesidades. Si quisiramos que a la izquierda del ttulo de cada elemento de la lista, se mostrara la cartula, slo debemos

pgina 24 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

modificar el layout listado_item.xml aadiendo un ImageView al cual habr que darle la direccin de la imagen al formar el listado. Bueno, con esto ya tenemos clara la apariencia de la pantalla; a continuacin tenemos el cdigo fuente de la misma: package peliculas; import java.util.List; import import import import import import import import android.app.Activity; android.content.Intent; android.os.Bundle; android.view.Menu; android.view.MenuItem; android.widget.ListView; android.widget.Toast; peliculas.ListaPeliculas;

public class ResultsActivity extends Activity { private List<Pelicula> list; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_listado); list = ((Peliculas)getApplicationContext()).lPeliculas.getMovieList(); ListadoAdapter lad = new ListadoAdapter(this, android.R.layout.simple_list_i tem_1, list); ListView lv = (ListView)findViewById(R.id.lvListado); lv.setAdapter(lad); } }

Al crear esta pantalla, coge la lista de pelculas de la variable global de la aplicacin y la conserva localmente en su propia variable privada (lneas 16 y 23). Las tres lneas siguientes instancian el listado en base a la lista de pelculas. En Android, un listview siempre se alimenta de un Adapter. Existen varios tipos. Sin entrar en ms detalle, el que ms nos conviene utilizar para nuestro ejemplo es el ArrayAdapter. Haremos una clase ArrayAdapter en nuestro directorio de clases res\peliculas. Cuando implementamos la super clase ArrayAdapter hacemos tambin la funcin getView() que es la que crea la visualizacin para cada elemento del listview (listado). package peliculas; import java.util.List;

pgina 25 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

import import import import import import import

android.content.Context; android.view.LayoutInflater; android.view.View; android.view.ViewGroup; android.widget.ArrayAdapter; android.widget.TextView; peliculas.ListadoPeliculas;

public class ListadoAdapter extends ArrayAdapter<Pelicula> { public List<Pelicula> list; private Context context; public ListadoAdapter(Context context, int textViewResourceId, List<Pelicula> ob jects) { super(context, textViewResourceId, objects); this.list = objects; this.context = context; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context. LAYOUT_INFLATER_SERVICE); View rowView = inflater.inflate(R.layout.listado_item, parent, false); TextView textView = (TextView) rowView.findViewById(R.id.listado_item_title) ; textView.setText(list.get(position).getTitulo()); return rowView; } }

El constructor recibe unos parmetros muy concretos: Context: La pantalla que instancia el adaptador. textViewResourceId: El identificador del control (View) que mostrar la informacin de cada elemento. Puedes pasar null o el identificador de algn control propio que hayas puesto en el layout. objects: La lista o array de elementos del listado. Lo interesante est en la funcin getView(); es la responsable de la visualizacin de cada elemento del listado. Como te habrs fijado, uno de sus parmetros es el ndice del elemento de nuestro array o lista de elementos. Este parmetro es position, as que cuando Android llame a esta funcin automticamente para visualizar el quinto elemento de nuestra lista de pelculas, simplemente coge dicho elemento de nuestra lista, coge tambin el TextView que hicimos en nuestro layout listado_item.xml y le asigna el ttulo del elemento pelcula. De igual modo para cualquier otro elemento, es el propio Android el que llamar a esta funcin cuando lo necesite, pasando al parmetro position aqul que necesite visualizar.

pgina 26 / 27

Aplicacin Android + Servicio PHP


by SamuGG - http://samuel-granados.com/blog/aplicacion-android-servicio-php/

Descargar cdigo fuente top

pgina 27 / 27
Powered by TCPDF (www.tcpdf.org)