Crear Un WebService Para Android Con Mysql, Php y Json

46
Crear Un Web Service Para Android Con Mysql, Php y Json ¿Deseas conectar una aplicación Android a Mysql? ¿Has intentado crear un web service con Php para la comunicación de datos de tu aplicativo web con tu aplicativo móvil android, pero aún no comprendes bien cómo hacerlo? Pues bien, en este artículo te mostraré algunas ideas sobre la creación de una aplicación android que consuma los datos de un servidor externo a través de Php, Mysql y Json. Para ello he creado una aplicación llamada “I Wish”, la cual permite a nuestros usuarios guardar una lista de deseos y metas que tienen en vida. Con este ejemplo podrás ver cómo implementar la inserción, edición, eliminación y consulta de datos a través de un Web Service. El código de la aplicación puedes obtenerlo presionando el siguiente botón: Descargar Código 1. ¿Qué Es Un Web Service? Un Web Service o Servicio Web es un aplicativo que facilita la interoperabilidad entre varios sistemas independientemente del del lenguaje programación o plataforma en que fueron desarrollados. Este debe tener una interfaz basada en un formato estándar entendible por las maquinas como lo es XML o JSON. Por ejemplo… Facebook es un aplicativo web construido con una determinada arquitectura y lenguajes de programación basados en el protocolo HTTP. S embargo podemos usar esta red social en nuestro dispositivo Android. ¿Cómo es posible esto, si la aplicación Android está construida con lenguaje Java? A través de un Web Service construido para gestionar todas aquellas operaciones sobre una base de datos alojada en los servidores de Facebook. Quiere decir que ambos aplicativos usan como puente la web para acceder a un solo repositorio de datos. Como ves, un Web Service se crea con funcionalidades que permitan obtener datos actualizados en tiempo real. El hecho de que sea dinám incorpora el uso de un lenguaje web para la gestión HTTP que en este caso será Php. 2. Requerimientos De La Aplicación Como leíste al inicio, la aplicación I Wish gestiona las metas y sueños de los usuarios permitiéndoles tener un registro completo. Básicamen alcance del proyecto se resumen en: Como usuario de I Wish, deseo mantener los datos de todas mis metas y sueños (se refiere al CRUD). Como usuario de I Wish, deseo ver el detalle de cada meta. Como usuario de I Wish, deseo que cada ítem tenga un título, una descripción, una fecha límite de cumplimiento, prioridad y categor

description

Aprende a crear un Web Service con Php, Mysql Y Json para consumirlo en una aplicación Android

Transcript of Crear Un WebService Para Android Con Mysql, Php y Json

  • Crear Un Web Service Para Android Con Mysql, Php y Json

    Deseas conectaruna aplicacin Android a Mysql?

    Has intentado crear un web service con Php para la comunicacin de datos de tu aplicativo web con tu aplicativo mvil android, pero an nocomprendes bien cmo hacerlo?

    Pues bien, en este artculo te mostrar algunas ideas sobre la creacin de una aplicacin android que consuma los datos de un servidorexterno a travs de Php, Mysql y Json.

    Para ello he creado una aplicacin llamada I Wish, la cual permite a nuestros usuarios guardar una lista de deseos y metas que tienen en suvida. Con este ejemplo podrs ver cmo implementar la insercin, edicin, eliminacin y consulta de datos a travs de un Web Service.

    El cdigo de la aplicacin puedes obtenerlo presionando el siguiente botn:

    Descargar Cdigo

    1. Qu Es Un Web Service?Un Web Service o Servicio Web es un aplicativoque facilita lainteroperabilidad entre varios sistemas independientemente del del lenguaje deprogramacin o plataforma en que fueron desarrollados. Este debe tener una interfaz basada en un formato estndar entendible por lasmaquinas como lo es XML o JSON.

    Por ejemplo

    Facebook es un aplicativo web construido con una determinada arquitectura y lenguajes de programacin basados en el protocolo HTTP. Sinembargo podemos usar esta red social en nuestro dispositivo Android.

    Cmo es posible esto, si laaplicacin Android est construida con lenguaje Java?

    A travs de un Web Service construido para gestionar todas aquellas operaciones sobre una base de datos alojada en los servidores deFacebook. Quiere decir que ambos aplicativos usan como puente la web para acceder a un solo repositorio de datos.

    Como ves, un Web Service se crea con funcionalidades que permitan obtener datos actualizados en tiempo real. El hecho de que sea dinmicoincorpora el uso de un lenguaje web para la gestin HTTP que en este caso ser Php.

    2. Requerimientos De La AplicacinComo leste al inicio, la aplicacin I Wish gestiona las metas y sueos de los usuarios permitindoles tener un registro completo. Bsicamente elalcance del proyecto se resumen en:

    Como usuario de I Wish, deseo mantener los datos de todas mis metas y sueos (se refiere al CRUD).Como usuario de I Wish, deseo ver el detalle de cada meta.Como usuario de I Wish, deseo que cada tem tenga un ttulo, una descripcin, una fecha lmite de cumplimiento, prioridad y categora.

  • Las categoras posibles son: Salud, Finanzas, Profesional y Espiritual.

    Estos requerimientos no son nada del otro mundo. Bsicamente estas ante una situacin de listas y detalles. Algo que ya has visto en artculospasados con gran frecuencia.

    El meollo del asunto se encuentra en el Web Service que debes crear con Php y Mysql para el mantenimiento de los datos. Esta vez nousaremos caching para el soporte de los datos locales como lo hicimos al crear el lector Rss. Nos enfocaremos en como usar Volley pararealizar las peticiones en el localhost.

    3. Wireframing De La AplicacinA primera vista I Wish es una aplicacin que se basa en la funcionalidad bsica de un crud. Tendremos una lista de los elementos que existen,podremos ver el detalle de cada uno, modificar su contenido e incluso borrarlos.

    Teniendo en cuenta este razonamiento, puedes imaginar la aplicacin en primera instancia de la siguiente forma:

    Basado en el boceto que acabas de crear ya puedes identificar que la cantidad de actividades, fragmentos, dilogos y formularios quenecesitas. As que veamos la siguiente lista de materiales a crear:

    Actividad principal con un fragmento de lista.Layout personalizado para items.Actividad con fragmento de detalle.Actividad con fragmento de formulariopara insercin.Actividad con fragmento de formulariopara edicin.

    En este tutorial usaremos actividades basadas en fragmentos, ya que muchos lectores han preguntado cmo hacer para comunicar fragmentoscon actividades y viceversa.

    4. Crear UI Para La Aplicacin Android4.1 Disear Actividad Principal Con Fragmento Tipo ListaDespus de haber creado t proyecto en Android Studio vas a crear una actividad principal que contengan un fragmento con una lista. Debidoa que vamos a aadir los fragmentos programticamente no es necesario enfocarnos tanto en los layouts de las actividades. Incluso puedesusar un solo layout para todas las actividades.

    activity_main.xml

  • android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"/>

    El fragmento pudiese heredar de ListFragment pero debido a que vamos a usar un RecyclerView , el diseo es diferente. La idea es aadir elrecycler para recubrir toda la actividad y adems aadir un Floating Action Button en la parte inferior derecha con el fin de que el usuarioaada nuevas metas.

    Para aadir el FAB (Floating Action Button) podemos hacer uso de una de las siguientes libreras que existen en la web:

    Floating Action Button Library For AndroidFloatingActionButton de makovkastarFuture Simple

    Incluso podras basarte en el ejemplo del sitio de android devepers llamado FloatingActionButtonBasic. Todo depende de ti. Cada librera traela explicacin de su implementacin, as que no hay excusas.

    Por mi parte, en este ejemplo usar la librera de makovkastar, ya que necesitamos fabs muy simples. Para ello incluimos la siguientedependencia deGradle:

    compile'com.melnykov:floatingactionbutton:1.3.0'

    Veamos como queda el layout del fragmento principal:

    fragment_main.xml

    Se usa una etiqueta para implementar el FAB. Simplemente se ubica en la parte inferior derecha y leaadimos los colores correspondientes a su interaccin.

    Donde colorNormal es el color que tiene en estado natural; colorPressed es aquel que se proyecta cuando lo presionamos rapidamente ycolorRipple se evidencia cuando mantienes un click largo sobre l.

    Otro aspecto a tener en cuenta es que los mipmaps o drawables que uses para elicono de un FABdebe tener dimensiones de 24dp, para unabuena experiencia de usuario:

  • El patrn anterior muestra un FAB grande para representar la insercin con unas dimensiones reglamentarias de 56dpx56dp. El icono que llevadebe mantenerse en 24dpx24dp.

    Tambin podemos tener un FAB mini con dimensiones de 40dpx40dp, donde el icono se mantiene sobre 24dpx24dp.

    4.2 Disear Actividad De Detalle Con Fragmento PersonalizadoAcudiendo a los estilos de layouts en Material Design, dividiremos el fragmento de detalle en dos pasos. El primero ser una ImageView alusivoa la categora de la meta y el segundo ser una hoja para sus datos completos. Adicionalmente aadiremos un Float Button Action para laedicin de la meta.

    fragment_detail.xml

  • El FAB debe usar el atributofab:fab_type=mini para usar el botn mini.

    En este caso se us como nodo un LinearLayout con dos RelativeLayout dentro. Esto nos permite dividir por pesos (weight) la ocupacin deespacio entre ambos layouts y as mantener una proporcin.

  • 4.3 Disear Actividad Con FormularioLa insercin y edicin requiere de la proyeccin de un formulario que contenga los controles necesarios para que el usuario especifique lainformacin personalizada que desea almacenar en la base de datos. Para ello debes crear un layout con los datos que viste en losrequerimientos de la aplicacin con las respectivos views para obtener la informacin.

    Por ejemplo

    El titulo de cada meta recibe texto escrito desde el input del dispositivo, por lo que sabemos que el EditText es la solucin para este caso. Ladescripcin es igual, necesita un campo de texto. La fecha limite puede ser obtenida a travs de un DatePicker y para la categora quetiene undominio de varias opciones, puedes usar un Spinner .

    Veamos:

  • android:layout_height="wrap_content"android:id="@+id/descripcion_input"android:layout_below="@+id/titulo_input"android:layout_centerHorizontal="true"android:hint="Descripcin"android:maxLength="128"android:nestedScrollingEnabled="true"android:paddingTop="16dp"android:paddingBottom="16dp"/>

  • 4.4 Disear Layout Personalizado De Los ItemsLa organizacin de los atributos de cada meta dentro de los tems de la lista debe ser un resumen de sus caractersticas principales. Puedesdejar la descripcin solo para la actividad del detalle y eliminarlo de la presentacin en la lista.

    item_list.xml

  • El anterior diseo se vera de la siguiente forma:

    5. Codificacin Del Web Service En PhpAntes de crear la aplicacin Android debes desarrollar primero tu Web Service con cualquiera de los estndares que te interesen. El alcance deeste tutorial no abarca el uso de restricciones REST, SOAP, RPC o sus parecidos. Simplemente vers cmo crear las implementaciones Phpnecesarias para realizar operaciones sobre una base de datos en Mysql a travs de peticiones GET y POST.

    Si deseas aprender a crear Web Services con diseo REST, entonces te recomiendo este excelente curso online con Laravel.

    Para desarrollar este aplicativo usar el entorno de desarrollo XAMPP, el cual provee automticamente una configuracin deunservidorApache local, el intrprete de Php y el gestor Mysql.

    Sin embargo tu puedes usar las herramientas que desees para gestionar pruebas locales. Lo importante es que puedas correr Mysql einterpretar scripts de Php.

    5.1 Diseo E Implementacin De La Base De DatosDisear base de datos: Siya lo has notado, la base de datos de la aplicacin I Wish solo tiene una entidad que representa a los registros de lasmetas. Esto reduce ampliamente el diseo de bases de datos en el problema. No obstante, si tu proyecto es mas complicado, asegrate detener una buena metodologa de diseo de bases de datos antes de crear el web service,

    Meta debe tener los atributos que hemos venido viendo ms una llave primaria que mantenga la integridad de los datos. Observa el siguienteminidiagrama entidad-relacin:

    Crear base de datos: Para implementar la base de datos lo primero que debes hacer es crear una nueva base de datos en la aplicacinphpMyAdmin que te otorga tu distribucin XAMPP. Donde le asignaremos el nombre de i_wish.

  • Ahora crea la tabla meta para que contenga seis columnas en su estructura y adems usa el formato UTF8 para soportar acentos. Puedeshacerlo a travs del editor de phpMyAdmin o conel siguiente comando CREATE :

    CREATETABLEIFNOTEXISTSmeta(idMetaint(3)PRIMARYKEYAUTO_INCREMENT,titulovarchar(56)NOTNULL,descripcionvarchar(128)NOTNULL,prioridadenum('Alta','Media','Baja','')NULLDEFAULT'Alta',fechaLimdateNOTNULL,categoriaenum('Salud','Finanzas','Espiritual','Profesional','Material')NOTNULLDEFAULT'Finanzas')

    Luego aade 5 registros de ejemplo en la tabla que permitan probar el funcionamiento en la aplicacin android ms adelante.

    INSERTINTO`i_wish`.`meta`(`idMeta`,`titulo`,`descripcion`,`prioridad`,`fechaLim`,`categoria`)VALUES(NULL,'ComprarMazda6','Deseoadquirirunautomazda6paramidesplazamientoenlaciudad.Deboinvestigarcmoconseguirmasfuentesdeingresos','Media','20151120','Material'),(NULL,'Obtenermittulodeingenieradesistemas','Yasolofaltan2semestresparaterminarmicarreradeingeniera.Deboprepararmealmximoparadesarrollarmitesisdegrado','Alta','20160617','Profesional'),(NULL,'ConquistaraNatasha','Natashaeslamujerdevida.Tengoquedecrseloantesdequeacabeelsemestre','Alta','20150525','Espiritual'),(NULL,'Tenerunpesode70kg','Actualmentepeso92kgyestoyensobrepeso.Sinembargovoyaseguirunarutinadeejerciciosyunrgimenalimenticio','Baja','20160513','Salud'),(NULL,'Incrementarun30%misingresos','Conseguirunafuentedeingresosalternativaquerepresentenun30%delosingresosquereciboactualmente.','Media','20151013','Finanzas');

    5.2 Crear Cdigo Php Para Consumir DatosEn primera instancia crea una conexin a la base de datos Mysql con la interfaz que mas se acomode a tus necesidades. En mi caso voy a crearuna conexin con PDO, la cual me permite proteger los datos de inyecciones sql.

    Luego de eso crea una clase que mapee la estructura de la tabla meta . El objetivo de ello es proveerla de comportamientos de insercin,actualizacin, eliminacin y consulta a travs de la conexin a la base de datos.

    Finalmente implementar scripts Php para gestionar las peticiones que lanzan los clientes. La idea es parsear los datos en formato Json paraque nuestra aplicacin Android interprete los resultados de forma legible.

    Paso #1: Crear conexin a la base de datos con PDOEl uso de PDO depende del enfoque que tengan tus proyectos, puedes crear una clase que represente la conexin hacia la base de datos osimplemente crear una nueva conexin en cada script de Php que tengas.

    Para este caso te compartir un patrn singleton de PDO para limitar el nmero de aperturas a la base de datos en una sola. Con ello podremosdisponer de un solo objeto a travs de todo el proyecto.

    No obstante hay patrones de diseo muy interesantes que puedes consultar en la web. Por ejemplo el repositorio delusuario indieteq engithub. l se enfoca en la implementacin del CRUD de una forma muy sencilla y orientada a objetos.

    Veamosel resultado del patrn singleton:

    Database.php

  • function_destructor(){self::$pdo=null;}}

    ?>

    Ten en cuenta que la conexin se abre con 4 cadenas descriptivas del entorno que ests usando declaradas en el archivo mysql_login.php. Conello me refiero al nombre del host, el nombre de la base de datos, el usuario con que deseas ingresar y su respectiva contrasea.

    Por el momento usaremos el localhost debido a las pruebas que estamos haciendo. El usuario ya depende de ti, en mi caso uso el usuario pordefecto "root" y sin contrasea alguna.

    mysql_login.php

    Adicionalmente debes aadir al cuarto parmetro del constructor de PDO la indicacin SETNAMESUTF8 para el servidor. Esto permite que losdatos de la base de datos vengan codificados en este formato para evitar problemas de compatibilidad.

    Paso #4: Crear clase para las metasEn este paso vas a modelar en una clase a la tabla "meta" de tal forma que aplique el CRUD sobre los datos a travs de la clase Database . Enesencia necesitas un mtodo para obtener todos los registros, uno para la insercin, otro para eliminacin, tambin para la actualizacin y unmtodo que permita obtener del detalle de un solo registro.

    Meta.php

  • returnfalse;}}

    /***Obtieneloscamposdeunametaconunidentificador*determinado**@param$idMetaIdentificadordelameta*@returnmixed*/publicstaticfunctiongetById($idMeta){//Consultadelameta$consulta="SELECTidMeta,titulo,descripcion,prioridad,fechaLim,categoriaFROMmetaWHEREidMeta=?";

    try{//Prepararsentencia$comando=Database::getInstance()>getDb()>prepare($consulta);//Ejecutarsentenciapreparada$comando>execute(array($idMeta));//Capturarprimerafiladelresultado$row=$comando>fetch(PDO::FETCH_ASSOC);return$row;

    }catch(PDOException$e){//Aqupuedesclasificarelerrordependiendodelaexcepcin//parapresentarloenlarespuestaJsonreturn1;}}

    /***Actualizaunregistrodelabasesdedatosbasado*enlosnuevosvaloresrelacionadosconunidentificador**@param$idMetaidentificador*@param$titulonuevotitulo*@param$descripcionnuevadescripcion*@param$fechaLimnuevafechalimitedecumplimiento*@param$categorianuevacategoria*@param$prioridadnuevaprioridad*/publicstaticfunctionupdate($idMeta,$titulo,$descripcion,$fechaLim,$categoria,$prioridad){//CreandoconsultaUPDATE$consulta="UPDATEmeta"."SETtitulo=?,descripcion=?,fechaLim=?,categoria=?,prioridad=?"."WHEREidMeta=?";

    //Prepararlasentencia$cmd=Database::getInstance()>getDb()>prepare($consulta);

    //Relacionaryejecutarlasentencia$cmd>execute(array($titulo,$descripcion,$fechaLim,$categoria,$prioridad,$idMeta));

    return$cmd;}

    /***Insertarunanuevameta**@param$titulotitulodelnuevoregistro

  • *@param$descripciondescripcindelnuevoregistro*@param$fechaLimfechalimitedelnuevoregistro*@param$categoriacategoriadelnuevoregistro*@param$prioridadprioridaddelnuevoregistro*@returnPDOStatement*/publicstaticfunctioninsert($titulo,$descripcion,$fechaLim,$categoria,$prioridad){//SentenciaINSERT$comando="INSERTINTOmeta("."titulo,"."descripcion,"."fechaLim,"."categoria,"."prioridad)"."VALUES(?,?,?,?,?)";

    //Prepararlasentencia$sentencia=Database::getInstance()>getDb()>prepare($comando);

    return$sentencia>execute(array($titulo,$descripcion,$fechaLim,$categoria,$prioridad));

    }

    /***Eliminarelregistroconelidentificadorespecificado**@param$idMetaidentificadordelameta*@returnboolRespuestadelaeliminacin*/publicstaticfunctiondelete($idMeta){//SentenciaDELETE$comando="DELETEFROMmetaWHEREidMeta=?";

    //Prepararlasentencia$sentencia=Database::getInstance()>getDb()>prepare($comando);

    return$sentencia>execute(array($idMeta));}}

    ?>

    Recuerda que el mtodo prepare() permite reemplazar los placeholders ( '?' ) a travs de execute() . Esto protege la operacin deinyecciones que puedan atentar contra la seguridad de los datos.

    Paso #5: Crear un scriptpara obtener todas las metasPara retornar todos los registros que existen en la tabla "meta" usaremos el mtodo getAll() de la clase Meta . La trata de la peticin seguirala siguiente lgica:

    1. Comprobar que la peticin se realiz con el mtodo GET.2. Obtener todos los registros.3. La obtencin tuvo xito?

    A. SI -> Retornar objeto Json con los datosB. NO -> Retornar objeto Json con mensaje de error

    Tenemos un flujo que se asegura de satisfacer el debido resultado y aquellos resultados adversos. La trata de errores debe comprender todos

  • aquellos posibles caminos que puedan generarse como una peticin fallida, la falla de autenticacin, la no existencia del recurso, la nodisponibilidad del servidor, etc. En resumen, contempla todas las fallas tanto del lado del servidor (cdigos5xx) como las del cliente (cdigos4xx).

    No obstante este ejemplo se basa en el comportamiento ideal de nuestro servidor local. Donde solo reportaremos aquellas anomalas quesucedan en la base de datos, asumiendo que la respuesta siempre tendr un cdigo de estado 200. Esto permitir trackear si nuestro webservice est operando bien la base de datos.

    Adems de ello PDO puede retornar en excepciones por distintas causas que puedes estandarizar para el envo de mensajes. Pero este trabajote queda a t

    AhoraCmo envo una respuesta de vuelta a la aplicacin Android?

    Es justo donde entra Json para actuar como formato de comunicacin. En cada respuesta enviaremos una seria de elementos Json que puedanser interpretados del lado del cliente. Esto te ser posible usando las funciones json_encode() y json_decode() . La primera parsea un tipo dedatoa un string en formato json y la segunda es el procedimiento contrario.

    Veamos nuestro servicio de obtencin:

    obtener_metas.php

  • "prioridad":"Alta","fechaLim":"20150525","categoria":"Espiritual"}]}

    Por el otro lado, la respuesta de error simplemente sera:

    {"estado":"2","mensaje":"Haocurridounerror"}

    Cambiando de temaQu pasa si quieres filtrar los registros?

    Por ejemplo

    Puede que requieras en orden ascendente o descendente de los registros con respecto a un campo. O simplemente obtener las metas que vande una fecha a otra.

    Para tener en cuenta estos casos, puedes consultar los datos de acuerdo a una serie de parmetros establecidos en la API. Esto quiere decirque podras incluir en el cuerpo de la peticin variables que acten como filtros enla seleccin.Sin embargo dicho tema est fuera del alcancede nuestro artculo.

    El diseo RESTful para Web Services provee reglas supremamente estilizadas para filtrar y consultar datos de forma ms sencilla queestableciendo filtros manuales.

    Paso #6: Crear un script php para consultar el detalle de una metaEl segundo caso requiere que la peticin traiga consigo el identificador de la meta que se desea ver en detalle. Con este dato es posible usar elmtodo getById() de Meta para conseguir el array necesario.

    Veamos:

  • );}

    }else{//Enviarrespuestadeerrorprintjson_encode(array('estado'=>'3','mensaje'=>'Senecesitaunidentificador'));}}

    Para retornar el detalle obviamente primero debes comprobar que el parmetro vino con la peticin GET y si vino bien definido. Recuerda quela funcin isset() es quin realiza este trabajo.

    Esta vez tenemos tres casos generales posibles. Que la consulta sea un xito y el registro con el identificador enviado existe. Lo que retorna enun objeto Json con un objeto interno que tiene los datos de la meta.

    {"estado":"1","meta":{"idMeta":"2","titulo":"Obtenermit\u00edtulodeingenier\u00edadesistemas","descripcion":"Yasolofaltan2semestresparaterminarmicarreradeingenier\u00eda.Deboprepararmealm\u00e1ximoparadesarrollarmitesisdegrado""prioridad":"Media","fechaLim":"20150529","categoria":"Profesional"}}

    O tambin puede que PDO haya arrojado una excepcin por algn motivo. Por ejemplo un error de sintaxis, la inexistencia del registro, etc. Conello envas tu objeto representativo del estado 2 .

    {"estado":"2","mensaje":"Noseobtuvoelregistro"}

    Ahora bien, puede que por alguna razn el parmetro no haya venido en la peticin, o que pueda que haya venido pero con otro nombre. Paraeste caso envas tu cdigo 3 indicando este mensaje.

    {"estado":"3","mensaje":"Senecesitaunidentificador"}

    Paso #7: Crear un script php para la insercin de metasLa insercin requiere el uso del mtodo POST para la recepcin de los datos de la meta. Por lo quedebemos leer los datos en formato Json:

  • $body['fechaLim'],$body['categoria'],$body['prioridad']);

    if($retorno){//Cdigodexitoprintjson_encode(array('estado'=>'1','mensaje'=>'Creacinexitosa'));}else{//Cdigodefallaprintjson_encode(array('estado'=>'2','mensaje'=>'Creacinfallida'));}}

    La primera instruccin es comprobar la peticin POST obtenida. Luego de ello conviertes el cuerpo de la peticin a un arreglo de strings. Esto esposible consultando el flujo con file_get_contents() , que convierte un archivo a string. Obviamentees necesario queuses la convencinphp://input para accederal cuerpo de la peticin POST.

    Ahora, el resultado que obtengas con file_get_contents() debe estar en formato Json, por lo que convertiremos esos datos a un arregloasociativo que nos permita acceder a la informacin. Para ello usa la funcin json_decode() y pasa como segundo parmetro el valor de true

    Luego usa el mtodo insert() de Meta y comprueba el resultado. Esta vez no retornas en filas de la base de datos, as que el estado 1contiene un mensaje de xito.

    {"estado":"1","mensaje":"Creacinxitosa"}

    De lo contrario usa un mensaje general de error.

    {"estado":"2","mensaje":"Creacinfallida"}

    Paso #8: Crear un scritp Php para la actualizacin de metasLa actualizacin es casi idntica a la insercin, solo que esa vez debemos obtener el identificador de la meta para saber que registro actualizar.De resto procedemos con el mtodo update() de Meta sin problemas:

  • //Cdigodexitoprintjson_encode(array('estado'=>'1','mensaje'=>'Actualizacinexitosa'));}else{//Cdigodefallaprintjson_encode(array('estado'=>'2','mensaje'=>'Actualizacinfallida'));}}

    Es resultado de xito es similar y repetitivo para la actualizacin:

    {"estado":"1","mensaje":"Actualizacinxitosa"}

    Al igual que el objeto Json de error:

    {"estado":"2","mensaje":"Actualizacinfallida"}

    Paso #9: Crear un script Php para la eliminacin de metasLa eliminacin se basa enel mtodo POST para enviar el identificador de la meta que se necesita eliminar de la base de datos. Esta vezusaremos el mtodo delete() de Meta .

  • Y los errores se mostraran as:

    {"estado":"2","mensaje":"Eliminacinfallida"}

    6. Codificacin De La Aplicacin AndroidUna vez creado el Web Service, es hora de construir nuestra aplicacin gestora de metas. Recuerda que es necesario que crees los siguienteselementos e interacciones de la arquitectura:

    Unpatrn singleton Volley para las peticiones (o un cliente HttpURLConnection si lo deseas).Crear la peticin personalizada para tratar respuestas Json (el cdigo ya fue tratado en el artculo de Volley).Crear un adaptador que procese los elementos del recycler view.Tratar los eventos para la comunicacin de datos a travs de los controles.

    La idea es enfocarnos en el uso del servicio web y aprovechar al mximo las peticiones Json que nos provee Volley.

    Paso #1:Crear Patrn Singleton VolleyEste paso ya hace parte de nuestra rutina para gestionar peticiones HTTP. As que reutilizars el singleton de artculos pasados para simplificarprocesos. La nica diferencia que tendrs ser la ausencia del ImageLoader como atributo. En esta ocasin no usaremos caching de imgenes,as que es justo dejarlo descansar.

    Recuerda incluir la librera Volley en tu proyecto de la forma que ms te parezca.

    VolleySingleton.java

    importandroid.content.Context;

    importcom.android.volley.Request;importcom.android.volley.RequestQueue;importcom.android.volley.toolbox.Volley;

    /***CreadoporHermosaProgramacin.**ClasequerepresentaunclienteHTTPVolley*/

    publicfinalclassVolleySingleton{

    //AtributosprivatestaticVolleySingletonsingleton;privateRequestQueuerequestQueue;privatestaticContextcontext;

    privateVolleySingleton(Contextcontext){VolleySingleton.context=context;requestQueue=getRequestQueue();}

    /***Retornalainstanciaunicadelsingleton*@paramcontextcontextodondeseejecutarnlaspeticiones*@returnInstancia*/publicstaticsynchronizedVolleySingletongetInstance(Contextcontext){if(singleton==null){singleton=newVolleySingleton(context.getApplicationContext());}returnsingleton;}

    /***Obtienelainstanciadelacoladepeticiones*@returncoladepeticiones

  • */publicRequestQueuegetRequestQueue(){if(requestQueue==null){requestQueue=Volley.newRequestQueue(context.getApplicationContext());}returnrequestQueue;}

    /***Aadelapeticinalacola*@paramreqpeticin*@paramResultadofinaldetipoT*/publicvoidaddToRequestQueue(Requestreq){getRequestQueue().add(req);}

    }

    Para acceder a las URLs del web service con aislamiento, crea una clase para referenciar constantes de la aplicacin. All aadirs todas lasdirecciones para evitar mltiples declaraciones:

    /***Clasequecontieneloscdigosusadosen"IWish"para*mantenerlaintegridadenlasinteraccionesentreactividades*yfragmentos*/publicclassConstantes{/***TransicinHome>Detalle*/publicstaticfinalintCODIGO_DETALLE=100;

    /***TransicinDetalle>Actualizacin*/publicstaticfinalintCODIGO_ACTUALIZACION=101;

    /***URLsdelWebService*/publicstaticfinalStringGET="http://10.0.3.2:63343/I%20Wish/obtener_metas.php";publicstaticfinalStringGET_BY_ID="http://10.0.3.2:63343/I%20Wish/obtener_meta_por_id.php";publicstaticfinalStringUPDATE="http://10.0.3.2:63343/I%20Wish/actualizar_meta.php";publicstaticfinalStringDELETE="http://10.0.3.2:63343/I%20Wish/borrar_meta.php";publicstaticfinalStringINSERT="http://10.0.3.2:63343/I%20Wish/insertar_meta.php";

    /***Claveparaelvalorextraquerepresentaalidentificadordeunameta*/publicstaticfinalStringEXTRA_ID="IDEXTRA";

    }

    Como ves, yo uso para el localhost la direccin 10.0.3.2 debido a que Genymotion (emulador alternativo) estableci este valor. Si vas a usar elemulador de android usa la direccin 10.0.2.2 . Aqu el sitio oficial te habla un poco mas sobre ests convenciones de direcciones paraoperaciones en la web.

    Paso #2:Crear fuente de datos para las metasNuestro adaptador necesita alimentarse de una lista de elementos que le proporcionen la informacin necesaria para proyectar el layout. Espor eso que tienes que crearuna clase que represente la existencia de una meta en la aplicacin Android.

    Crea una nueva clase en Android Studio y llmala Meta . Pon todos aquellos atributos puestos en la base de datos:

    /***Reflejodelatabla'meta'enlabasededatos*/publicclassMeta{

    /*Atributos

  • */privateStringidMeta;privateStringtitulo;privateStringdescripcion;privateStringprioridad;privateStringfechaLim;privateStringcategoria;

    publicMeta(StringidMeta,Stringtitulo,Stringdescripcion,Stringprioridad,StringfechaLim,Stringcategoria){this.idMeta=idMeta;this.titulo=titulo;this.descripcion=descripcion;this.prioridad=prioridad;this.fechaLim=fechaLim;this.categoria=categoria;}

    publicStringgetIdMeta(){returnidMeta;}

    publicStringgetTitulo(){returntitulo;}

    publicStringgetDescripcion(){returndescripcion;}

    publicStringgetPrioridad(){returnprioridad;}

    publicStringgetFechaLim(){returnfechaLim;}

    publicStringgetCategoria(){returncategoria;}

    /***Comparalosatributosdedosmetas*@parammetaMetaexterna*@returntruesisoniguales,falsesihaycambios*/publicbooleancompararCon(Metameta){returnthis.titulo.compareTo(meta.titulo)==0&&this.descripcion.compareTo(meta.descripcion)==0&&this.fechaLim.compareTo(meta.fechaLim)==0&&this.categoria.compareTo(meta.categoria)==0&&this.prioridad.compareTo(meta.prioridad)==0;}}

    Si te fijas, tenemos un mtodo para comparar una meta con otra para determinar si son iguales o no. Este mtodo ser de gran ayuda almomento de validar si hay cambios en los datos de los formularios cuando el usuario interacta con ellos. Lo que permitir determinar si hayque lanzar dilogos de confirmacin antes de aplicar acciones.

    Paso #3:Crear adaptador personalizado para el Recycler ViewEn este paso debes relacionar el layout item_list.xml con los datos que tenga cada objeto Meta de la fuente de datos.

    No olvides usar le patrn ViewHolder para reducir la cantidad de llamadas del mtodo findViewById().

    Adems de ello tenemos que implementar sobre cada view holderuna escucha OnClickListener para recibir los eventos del usuario en la lista.Para ello se crear una interfaz intermediaria entre el ViewHolder y el adaptador, de tal forma que cuando se active el evento onClick() esteinicie la actividad de detalle.

    importandroid.app.Activity;importandroid.content.Context;importandroid.support.v7.widget.RecyclerView;importandroid.view.LayoutInflater;

  • importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.TextView;

    importcom.herprogramacion.iwish.R;importcom.herprogramacion.iwish.modelo.Meta;importcom.herprogramacion.iwish.ui.actividades.DetailActivity;

    importjava.util.List;

    /***Adaptadordelrecyclerview*/publicclassMetaAdapterextendsRecyclerView.AdapterimplementsItemClickListener{

    /***Listadeobjetos{@linkMeta}querepresentanlafuentededatos*deinflado*/privateListitems;

    /*Contextodondeactuaelrecyclerview*/privateContextcontext;

    publicMetaAdapter(Listitems,Contextcontext){this.context=context;this.items=items;}

    @OverridepublicintgetItemCount(){returnitems.size();}

    @OverridepublicMetaViewHolderonCreateViewHolder(ViewGroupviewGroup,inti){Viewv=LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_list,viewGroup,false);returnnewMetaViewHolder(v,this);}

    @OverridepublicvoidonBindViewHolder(MetaViewHolderviewHolder,inti){viewHolder.titulo.setText(items.get(i).getTitulo());viewHolder.prioridad.setText(items.get(i).getPrioridad());viewHolder.fechaLim.setText(items.get(i).getFechaLim());viewHolder.categoria.setText(items.get(i).getCategoria());}

    /***Sobrescrituradelmtododelainterfaz{@linkItemClickListener}**@paramviewitemactual*@parampositionposicindelitemactual*/@OverridepublicvoidonItemClick(Viewview,intposition){DetailActivity.launch((Activity)context,items.get(position).getIdMeta());}

    publicstaticclassMetaViewHolderextendsRecyclerView.ViewHolderimplementsView.OnClickListener{//CamposrespectivosdeunitempublicTextViewtitulo;publicTextViewprioridad;publicTextViewfechaLim;publicTextViewcategoria;publicItemClickListenerlistener;

    publicMetaViewHolder(Viewv,ItemClickListenerlistener){super(v);

  • titulo=(TextView)v.findViewById(R.id.titulo);prioridad=(TextView)v.findViewById(R.id.prioridad);fechaLim=(TextView)v.findViewById(R.id.fecha);categoria=(TextView)v.findViewById(R.id.categoria);this.listener=listener;v.setOnClickListener(this);}

    @OverridepublicvoidonClick(Viewv){listener.onItemClick(v,getAdapterPosition());}}}

    interfaceItemClickListener{voidonItemClick(Viewview,intposition);}

    ItemClickListener es la interfaz de comunicacin que nos ayudar a relacionar lo posicin del view con el evento onClick() . Como ves seimplementa en la clase MetaAdapter para iniciar la actividad detalle a travs de su mtodo de fabricacin launch() .

    Es necesario que enviemos el identificador de la meta para tener una referencia de la meta que debemos detallar.

    Esto significa que se debe realizar otra peticin para obtener los datos de la meta seleccionada. Lo que podra evitarsea travs de caching conSQLite o enviando todos los datos de la meta. Sin embargo el fin de este tutorial es el uso al mximo de nuestro Web Service para que puedasinteriorizar el conocimiento y practicar esta metodologa. Por ahora no te preocupes en la arquitectura u optimizaciones.

    Paso #4: Realizar Peticin Para Poblar La ListaYa has construido un Web Service en Php con todas lascaractersticas necesariasy has desarrollado los componentes de software para que laaplicacin Android comience a funcionar.

    El fragmento de la lista lo iniciaremos dinmicamente a travs del mtodo onCreate() de MainActivity :

    importandroid.content.Intent;importandroid.os.Bundle;importandroid.support.v7.app.AppCompatActivity;

    importcom.herprogramacion.iwish.R;importcom.herprogramacion.iwish.ui.fragmentos.MainFragment;

    /***Actividadprincipalquecontieneunfragmentoconunalista.*Recuerdaquelanuevalibreradesoportereemplazlaclase*{@linkandroid.support.v7.app.ActionBarActivity}por*{@linkAppCompatActivity}paraelusodelaactionbar*enversionesantiguas.*/publicclassMainActivityextendsAppCompatActivity{

    @OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

    //Creacindelfragmentoprincipalif(savedInstanceState==null){getSupportFragmentManager().beginTransaction().add(R.id.container,newMainFragment(),"MainFragment").commit();}}}

    La comunicacin inicial con el servidor es la lectura de todas las metas que se han guardado hasta el momento. Con ellas poblaremos la lista apenas inicie la aplicacin. Por lo que debemos dirigirnos al fragmento principal y generar una peticin GET hacia el servidor en onCreateView()

    Veamos:

  • importandroid.content.Intent;importandroid.os.Bundle;importandroid.support.v4.app.Fragment;importandroid.support.v7.widget.LinearLayoutManager;importandroid.support.v7.widget.RecyclerView;importandroid.util.Log;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.Toast;

    importcom.android.volley.Request;importcom.android.volley.Response;importcom.android.volley.VolleyError;importcom.android.volley.toolbox.JsonObjectRequest;importcom.google.gson.Gson;importcom.herprogramacion.iwish.R;importcom.herprogramacion.iwish.modelo.Meta;importcom.herprogramacion.iwish.tools.Constantes;importcom.herprogramacion.iwish.ui.MetaAdapter;importcom.herprogramacion.iwish.ui.actividades.InsertActivity;importcom.herprogramacion.iwish.web.VolleySingleton;

    importorg.json.JSONArray;importorg.json.JSONException;importorg.json.JSONObject;

    importjava.util.Arrays;

    /***Fragmentoprincipalquecontienelalistadelasmetas*/publicclassMainFragmentextendsFragment{

    /*Etiquetadedepuracion*/privatestaticfinalStringTAG=MainFragment.class.getSimpleName();

    /*Adaptadordelrecyclerview*/privateMetaAdapteradapter;

    /*Instanciaglobaldelrecyclerview*/privateRecyclerViewlista;

    /*instanciaglobaldeladministrador*/privateRecyclerView.LayoutManagerlManager;

    /*InstanciaglobaldelFAB*/com.melnykov.fab.FloatingActionButtonfab;privateGsongson=newGson();

    publicMainFragment(){}

    @OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){

    Viewv=inflater.inflate(R.layout.fragment_main,container,false);

    lista=(RecyclerView)v.findViewById(R.id.reciclador);lista.setHasFixedSize(true);

    //UsarunadministradorparaLinearLayoutlManager=newLinearLayoutManager(getActivity());lista.setLayoutManager(lManager);

  • //CargardatoseneladaptadorcargarAdaptador();

    //ObtenerinstanciadelFABfab=(com.melnykov.fab.FloatingActionButton)v.findViewById(R.id.fab);

    //AsignarescuchaalFABfab.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){//IniciaractividaddeinsercingetActivity().startActivityForResult(newIntent(getActivity(),InsertActivity.class),3);}});

    returnv;}

    /***Cargaeladaptadorconlasmetasobtenidas*enlarespuesta*/publicvoidcargarAdaptador(){//PeticinGETVolleySingleton.getInstance(getActivity()).addToRequestQueue(newJsonObjectRequest(Request.Method.GET,Constantes.GET,null,newResponse.Listener(){

    @OverridepublicvoidonResponse(JSONObjectresponse){//ProcesarlarespuestaJsonprocesarRespuesta(response);}},newResponse.ErrorListener(){@OverridepublicvoidonErrorResponse(VolleyErrorerror){Log.d(TAG,"ErrorVolley:"+error.getMessage());}}

    ));}

    /***Interpretalosresultadosdelarespuestayas*realizarlasoperacionescorrespondientes**@paramresponseObjetoJsonconlarespuesta*/privatevoidprocesarRespuesta(JSONObjectresponse){try{//Obteneratributo"estado"Stringestado=response.getString("estado");

    switch(estado){case"1"://EXITO//Obtenerarray"metas"JsonJSONArraymensaje=response.getJSONArray("metas");//ParsearconGsonMeta[]metas=gson.fromJson(mensaje.toString(),Meta[].class);//Inicializaradaptadoradapter=newMetaAdapter(Arrays.asList(metas),getActivity());//Setearadaptadoralalistalista.setAdapter(adapter);break;case"2"://FALLIDOStringmensaje2=response.getString("mensaje");

  • Toast.makeText(getActivity(),mensaje2,Toast.LENGTH_LONG).show();break;}

    }catch(JSONExceptione){e.printStackTrace();}

    }

    }

    El cdigo anterior muestra el usode una constante llamada Constantes.GET, la cual contiene la direccin del servicio de obtencinobtener_metas.php.

    Con esa URL ya es posible realizar la peticin JsonObjectRequest con su respectivo mtodo GET a travs del mtodo cargarAdaptador() .

    Para aislar un poco los procesos, he creado el mtodo procesarRespuesta() , el cual recibe un objeto JSONObject en bruto para comenzar elparsing. Donde he divido los caminos a travs de una estructura switch basado en el valor del atributo "estado" .

    Si el estado es exitoso inmediatamente obtendremos el array de metas que viene en el atributo "metas" . Este arreglo de objetos Json se parseadirectamente a un arreglo de objetos Meta a travs de la librera Gson.

    Recuerda que el adaptador recibe una serie de metas en formato List , por lo que usaremos la clase Arrays para convertir el arreglo demetas a lista. Con eso listo ya es posible instanciar el adaptador y asignarlo al recycler.

    Paso #5: Ver Detalle De Items En Otra ActividadUna vez nuestro adaptador poblado, ya podemos ver el detalle de la descripcin en DetailActivity.java con un fragmento alojado.

    Para ello inicia el fragmento dinmicamente en onCreate():

    DetailActivity.java

    importandroid.app.Activity;importandroid.content.Context;importandroid.content.Intent;importandroid.os.Bundle;importandroid.support.v7.app.AppCompatActivity;importandroid.view.Menu;importandroid.view.MenuItem;

    importcom.herprogramacion.iwish.R;importcom.herprogramacion.iwish.tools.Constantes;importcom.herprogramacion.iwish.ui.fragmentos.DetailFragment;

    /***Estaactividadcontieneunfragmentoquemuestraeldetalle*delasmetas.*/publicclassDetailActivityextendsAppCompatActivity{

    /*Valorextraqueidentificaalametaadetallar*/privatestaticfinalStringEXTRA_ID="IDMETA";

    /***Instanciaglobaldelametaadetallar*/privateStringidMeta;

    /***Iniciaunanuevainstanciadelaactividad**@paramactivityContextodesdedondeselanzar*@paramidMetaIdentificadordelametaadetallar

  • */publicstaticvoidlaunch(Activityactivity,StringidMeta){Intentintent=getLaunchIntent(activity,idMeta);activity.startActivityForResult(intent,Constantes.CODIGO_DETALLE);}

    /***ConstruyeunIntentapartirdelcontextoylaactividad*dedetalle.**@paramcontextContextodondeseinicia*@paramidMetaIdentificadordelameta*@returnIntentlistoparausar*/publicstaticIntentgetLaunchIntent(Contextcontext,StringidMeta){Intentintent=newIntent(context,DetailActivity.class);intent.putExtra(EXTRA_ID,idMeta);returnintent;}

    @OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

    if(getSupportActionBar()!=null){//DehabilitartitulodelaactividadgetSupportActionBar().setDisplayShowTitleEnabled(false);//Setearcono"X"comoUpbuttongetSupportActionBar().setHomeAsUpIndicator(R.mipmap.ic_close);}

    //Retenerinstanciaif(getIntent().getStringExtra(EXTRA_ID)!=null)idMeta=getIntent().getStringExtra(EXTRA_ID);

    if(savedInstanceState==null){getSupportFragmentManager().beginTransaction().add(R.id.container,DetailFragment.createInstance(idMeta),"DetailFragment").commit();}}

    @OverridepublicbooleanonCreateOptionsMenu(Menumenu){getMenuInflater().inflate(R.menu.menu_detail,menu);returntrue;}

    @OverridepublicbooleanonOptionsItemSelected(MenuItemitem){intid=item.getItemId();

    switch(id){caseandroid.R.id.home:finish();returntrue;}

    returnsuper.onOptionsItemSelected(item);}}

    Este cdigo tiene varias cosas interesantes. En primera instancia el uso de un mtodo esttico llamado launch() , el cual construye unainstancia de la actividad de detalle y la inicia a travs de un Intent construido a partir del contexto que el adaptador proveer.

    La actividad detalle se basa en el identificador de la meta, por lo que idMeta es un atributo que permitir retener esa instancia, cuando seapedida con getIntent() .

    A los fragmentos que hemos iniciado dinmicamente se les est asignando una etiqueta que los diferencie de los otros. Esto es de supremaimportancia, ya que necesitamos obtener sus instancias cuando la actividad se comunique con ellos.

    Paso #9: Consultar Detalles De Cada Item

  • Ahora pregntate que debe hacer el fragmento de detalle

    Dependiendo del enfoque de experiencia de usuario que tengas, puede que sean muchas cosas. Sin embargopara este ejemplo el usuariotiene dos caminos evidentes:

    Cerrarel detallecon el Up Button o Back ButtonEditar la meta a travs del Floating Action Button.

    La primera interaccin ya la tenemos cubierta en DetailActivity , ya que hemos sobrescrito el comportamiento del Up Button por el cierre dela actividad.

    En el segundo caso de edicin es necesario consultar la base de datos para setear los datos en los views. Adems de ello asignar una escucha alFAB para que inicie la actividad de actualizacin.

    Realizar peticin HTTP: La realizacin delapeticin HTTP requiere consultar el detalle con el identificador que el adaptador envo a travs delIntent.

    Recuerda que la convencin createInstance() inicializa un nuevo fragmento con los extras necesarios para su funcionamiento. Por lo que enonCreateView() es posible acceder al identificador y enviar una peticin GET hacia el Web Service:

    DetailFragment.java

    importandroid.content.Intent;importandroid.os.Bundle;importandroid.support.v4.app.Fragment;importandroid.util.Log;importandroid.view.LayoutInflater;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.ImageButton;importandroid.widget.ImageView;importandroid.widget.TextView;importandroid.widget.Toast;

    importcom.android.volley.Request;importcom.android.volley.Response;importcom.android.volley.VolleyError;importcom.android.volley.toolbox.JsonObjectRequest;importcom.google.gson.Gson;importcom.herprogramacion.iwish.R;importcom.herprogramacion.iwish.modelo.Meta;importcom.herprogramacion.iwish.tools.Constantes;importcom.herprogramacion.iwish.ui.actividades.UpdateActivity;importcom.herprogramacion.iwish.web.VolleySingleton;

    importorg.json.JSONException;importorg.json.JSONObject;

    /***Aplaceholderfragmentcontainingasimpleview.*/publicclassDetailFragmentextendsFragment{/*Etiquetadevalorextra*/privatestaticfinalStringEXTRA_ID="IDMETA";

    /***Etiquetadedepuracin*/privatestaticfinalStringTAG=DetailFragment.class.getSimpleName();

    /*InstanciasdeViews*/privateImageViewcabecera;privateTextViewtitulo;privateTextViewdescripcion;privateTextViewprioridad;privateTextViewfechaLim;

  • privateTextViewcategoria;privateImageButtoneditButton;privateStringextra;privateGsongson=newGson();

    publicDetailFragment(){}

    publicstaticDetailFragmentcreateInstance(StringidMeta){DetailFragmentdetailFragment=newDetailFragment();Bundlebundle=newBundle();bundle.putString(EXTRA_ID,idMeta);detailFragment.setArguments(bundle);returndetailFragment;}

    @OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){Viewv=inflater.inflate(R.layout.fragment_detail,container,false);

    //Obtencindeviewscabecera=(ImageView)v.findViewById(R.id.cabecera);titulo=(TextView)v.findViewById(R.id.titulo);descripcion=(TextView)v.findViewById(R.id.descripcion);prioridad=(TextView)v.findViewById(R.id.prioridad);fechaLim=(TextView)v.findViewById(R.id.fecha);categoria=(TextView)v.findViewById(R.id.categoria);editButton=(ImageButton)v.findViewById(R.id.fab);

    //SetearescuchaparaelfabeditButton.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){//IniciaractividaddeactualizacinIntenti=newIntent(getActivity(),UpdateActivity.class);i.putExtra(EXTRA_ID,extra);getActivity().startActivityForResult(i,Constantes.CODIGO_ACTUALIZACION);}});

    //Obtenerextradelintentdeenvoextra=getArguments().getString(EXTRA_ID);

    //CargardatosdesdeelwebservicecargarDatos();

    returnv;}

    /***Obtienelosdatosdesdeelservidor*/publicvoidcargarDatos(){

    //AadirparmetroalaURLdelwebserviceStringnewURL=Constantes.GET_BY_ID+"?idMeta="+extra;

    //RealizarpeticinGET_BY_IDVolleySingleton.getInstance(getActivity()).addToRequestQueue(newJsonObjectRequest(Request.Method.GET,newURL,null,newResponse.Listener(){

    @OverridepublicvoidonResponse(JSONObjectresponse){//ProcesarrespuestaJsonprocesarRespuesta(response);}},newResponse.ErrorListener(){@OverridepublicvoidonErrorResponse(VolleyErrorerror){

  • Log.d(TAG,"ErrorVolley:"+error.getMessage());}}));}

    /***Procesacadaunodelosestadosposiblesdela*respuestaenviadadesdeelservidor**@paramresponseObjetoJson*/privatevoidprocesarRespuesta(JSONObjectresponse){

    try{//Obteneratributo"mensaje"Stringmensaje=response.getString("estado");

    switch(mensaje){case"1"://Obtenerobjeto"meta"JSONObjectobject=response.getJSONObject("meta");

    //ParsearobjetoMetameta=gson.fromJson(object.toString(),Meta.class);

    //Asignarcolordelfondoswitch(meta.getCategoria()){case"Salud":cabecera.setBackgroundColor(getResources().getColor(R.color.saludColor));break;case"Finanzas":cabecera.setBackgroundColor(getResources().getColor(R.color.finanzasColor));break;case"Espiritual":cabecera.setBackgroundColor(getResources().getColor(R.color.espiritualColor));break;case"Profesional":cabecera.setBackgroundColor(getResources().getColor(R.color.profesionalColor));break;case"Material":cabecera.setBackgroundColor(getResources().getColor(R.color.materialColor));break;}

    //Seteandovaloresenlosviewstitulo.setText(meta.getTitulo());descripcion.setText(meta.getDescripcion());prioridad.setText(meta.getPrioridad());fechaLim.setText(meta.getFechaLim());categoria.setText(meta.getCategoria());

    break;

    case"2":Stringmensaje2=response.getString("mensaje");Toast.makeText(getActivity(),mensaje2,Toast.LENGTH_LONG).show();break;

    case"3":Stringmensaje3=response.getString("mensaje");Toast.makeText(getActivity(),mensaje3,Toast.LENGTH_LONG).show();break;}

    }catch(JSONExceptione){e.printStackTrace();}

  • }}

    Para la inclusin de parmetros en la peticin GET, adjunta a la URL el valor de idMeta con la convencin de formularios '?clave=valor' .

    Al igual que en MainFragment , se cre un mtodo para procesar la respuesta dependiendo del estado que se obtuvo. Si hubo xito, entoncesseteamos los valores correspondientes de cada view.

    Paso #10: Realizar peticin POST para editar detalles de la metaPara la edicin hemos creado la actividad UpdateActivity , la cual mostrar el formulario de recoleccin con losdatos de la una meta.

    La lgica funciona as: Una vez el usuario haya modificado los datos, entonces puede confirmar sus datos presionando el action button de checkque usaremos para la confirmacin. Si no est de acuerdo o se arrepiente de ello, entonces puede descartar los cambios con el segundo actionbutton.Incluso puedes incluir la eliminacin entre los action buttos.

    As que lo primero es crear un archivo de men para poblar la action bar:

    menu_form.xml

    No incluiremos el guardado de cambios, ya que lo implementaremos en el Up Button.

    Teniendo en cuenta esa apreciacin las tareas que tienes porimplementar son:

    Cargar los datos de la meta en los componentes del formulario.Habilitar la contribucin a la action bar.Manejar los eventos en cada action button.Implementar la insercin, eliminacin y borrado de las metas.Lanzar dilogos para confirmar la eliminacin y el descarte de cambios.Usar Toasts para afianzar la confirmacin de las operaciones.

    Veamos la solucin:

    UpdateFragment.java

    importandroid.app.Activity;importandroid.os.Bundle;importandroid.support.v4.app.DialogFragment;importandroid.support.v4.app.Fragment;importandroid.util.Log;importandroid.view.LayoutInflater;importandroid.view.MenuItem;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.EditText;importandroid.widget.Spinner;importandroid.widget.TextView;importandroid.widget.Toast;

    importcom.android.volley.Request;importcom.android.volley.Response;importcom.android.volley.VolleyError;importcom.android.volley.toolbox.JsonObjectRequest;

  • importcom.google.gson.Gson;importcom.herprogramacion.iwish.R;importcom.herprogramacion.iwish.modelo.Meta;importcom.herprogramacion.iwish.tools.Constantes;importcom.herprogramacion.iwish.web.VolleySingleton;

    importorg.json.JSONException;importorg.json.JSONObject;

    importjava.util.HashMap;importjava.util.Map;

    /***Fragmentoconformularioparaactualizarlameta*/publicclassUpdateFragmentextendsFragment{/*Etiquetadedepuracin*/privatestaticfinalStringTAG=UpdateFragment.class.getSimpleName();

    /*Etiquetadevalorextraparamodoedicin*/privatestaticfinalStringEXTRA_ID="IDMETA";

    /*Controles*/privateEditTexttitulo_input;privateEditTextdescripcion_input;privateSpinnerprioridad_spinner;privateTextViewfecha_text;privateSpinnercategoria_spinner;

    /*Valordelargumentoextra*/privateStringidMeta;

    /***EslametaobtenidacomorespuestadelapeticinHTTP*/privateMetametaOriginal;

    /***InstanciaGsonparaelparsingJson*/privateGsongson=newGson();

    publicUpdateFragment(){}

    /***Creaunnuevofragmentobasadoenunargumento**@paramextraArgumentodeentrada*@returnNuevofragmento*/publicstaticFragmentcreateInstance(Stringextra){UpdateFragmentdetailFragment=newUpdateFragment();Bundlebundle=newBundle();bundle.putString(EXTRA_ID,extra);detailFragment.setArguments(bundle);returndetailFragment;}

    @OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){

    //InflandolayoutdelfragmentoViewv=inflater.inflate(R.layout.fragment_form,container,false);

    //Obtencindeinstanciascontroles

  • titulo_input=(EditText)v.findViewById(R.id.titulo_input);descripcion_input=(EditText)v.findViewById(R.id.descripcion_input);fecha_text=(TextView)v.findViewById(R.id.fecha_ejemplo_text);categoria_spinner=(Spinner)v.findViewById(R.id.categoria_spinner);prioridad_spinner=(Spinner)v.findViewById(R.id.prioridad_spinner);

    fecha_text.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){DialogFragmentpicker=newDatePickerFragment();picker.show(getFragmentManager(),"datePicker");

    }});

    //ObtenervalorextraidMeta=getArguments().getString(EXTRA_ID);

    if(idMeta!=null){cargarDatos();}

    returnv;}

    /***Obtienelosdatosdesdeelservidor*/privatevoidcargarDatos(){//AadiendoidMetacomoparmetroalaURLStringnewURL=Constantes.GET_BY_ID+"?idMeta="+idMeta;

    //ConsultareldetalledelametaVolleySingleton.getInstance(getActivity()).addToRequestQueue(newJsonObjectRequest(Request.Method.GET,newURL,null,newResponse.Listener(){

    @OverridepublicvoidonResponse(JSONObjectresponse){//ProcesalarespuestaGET_BY_IDprocesarRespuestaGet(response);}},newResponse.ErrorListener(){@OverridepublicvoidonErrorResponse(VolleyErrorerror){Log.d(TAG,"ErrorVolley:"+error.getMessage());}}));}

    /***Procesalarespuestadeobtencinobtenidadesdeelsevidor**/privatevoidprocesarRespuestaGet(JSONObjectresponse){

    try{Stringestado=response.getString("estado");

    switch(estado){case"1":JSONObjectmeta=response.getJSONObject("meta");//GuardarinstanciametaOriginal=gson.fromJson(meta.toString(),Meta.class);//SetearvaloresdelametacargarViews(metaOriginal);break;

    case"2":Stringmensaje=response.getString("mensaje");

  • //MostrarmensajeToast.makeText(getActivity(),mensaje,Toast.LENGTH_LONG).show();//EnviarcdigodefallagetActivity().setResult(Activity.RESULT_CANCELED);//TerminaractividadgetActivity().finish();break;}}catch(JSONExceptione){e.printStackTrace();}}

    /***Cargalosdatosinicialesdelformularioconlos*atributosdeunobjeto{@linkMeta}**@parammetaInstancia*/privatevoidcargarViews(Metameta){//Seteandovaloresdelarespuestatitulo_input.setText(meta.getTitulo());descripcion_input.setText(meta.getDescripcion());fecha_text.setText(meta.getFechaLim());

    //ObteniendoaccesoalosarraydestringsparacategoriasyprioridadesString[]categorias=getResources().getStringArray(R.array.entradas_categoria);String[]prioridades=getResources().getStringArray(R.array.entradas_prioridad);

    //Obteniendolaposicindelspinnercategoriasintposicion_categoria=0;for(inti=0;i

  • Stringtitulo=titulo_input.getText().toString();Stringdescripcion=descripcion_input.getText().toString();Stringfecha=fecha_text.getText().toString();Stringcategoria=(String)categoria_spinner.getSelectedItem();Stringprioridad=(String)prioridad_spinner.getSelectedItem();

    returnnewMeta("0",titulo,descripcion,fecha,categoria,prioridad);}

    @OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setHasOptionsMenu(true);//ContribucinalaAB}

    @OverridepublicbooleanonOptionsItemSelected(MenuItemitem){intid=item.getItemId();

    switch(id){caseandroid.R.id.home://CONFIRMARif(!validarCambios())guardarMeta();else//Terminaractividad,yaquenohaycambiosgetActivity().finish();returntrue;

    caseR.id.action_delete://ELIMINARmostrarDialogo(R.string.dialog_delete_msg);break;

    caseR.id.action_discard://DESCARTARif(!validarCambios()){mostrarDialogo(R.string.dialog_discard_msg);}else//Terminaractividad,yaquenohaycambiosgetActivity().finish();break;

    };

    returnsuper.onOptionsItemSelected(item);}

    /***Guardaloscambiosdeunametaeditada.**Siestenmodoinsercin,entoncescreaunanueva*metaenlabasededatos*/privatevoidguardarMeta(){

    //ObtenervaloresactualesdeloscontrolesfinalStringtitulo=titulo_input.getText().toString();finalStringdescripcion=descripcion_input.getText().toString();finalStringfecha=fecha_text.getText().toString();finalStringcategoria=categoria_spinner.getSelectedItem().toString();finalStringprioridad=prioridad_spinner.getSelectedItem().toString();

    HashMapmap=newHashMap();//Mapeoprevio

    map.put("idMeta",idMeta);map.put("titulo",titulo);map.put("descripcion",descripcion);map.put("fechaLim",fecha);map.put("categoria",categoria);map.put("prioridad",prioridad);

    //CrearnuevoobjetoJsonbasadoenelmapaJSONObjectjobject=newJSONObject(map);

    //DepurandoobjetoJson...Log.d(TAG,jobject.toString());

  • //ActualizardatosenelservidorVolleySingleton.getInstance(getActivity()).addToRequestQueue(newJsonObjectRequest(Request.Method.POST,Constantes.UPDATE,jobject,newResponse.Listener(){@OverridepublicvoidonResponse(JSONObjectresponse){procesarRespuestaActualizar(response);}},newResponse.ErrorListener(){@OverridepublicvoidonErrorResponse(VolleyErrorerror){Log.d(TAG,"ErrorVolley:"+error.getMessage());}}

    ){@OverridepublicMapgetHeaders(){Mapheaders=newHashMap();headers.put("ContentType","application/json;charset=utf8");headers.put("Accept","application/json");returnheaders;}

    @OverridepublicStringgetBodyContentType(){return"application/json;charset=utf8"+getParamsEncoding();}});

    }

    /***Procesatodoslastareasparaeliminar*unametaenlaaplicacin.Estemtodosoloseusa*enlaedicin*/publicvoideliminarMeta(){

    HashMapmap=newHashMap();//MAPEO

    map.put("idMeta",idMeta);//Identificador

    JSONObjectjobject=newJSONObject(map);//ObjetoJson

    //EliminardatosenelservidorVolleySingleton.getInstance(getActivity()).addToRequestQueue(newJsonObjectRequest(Request.Method.POST,Constantes.DELETE,jobject,newResponse.Listener(){@OverridepublicvoidonResponse(JSONObjectresponse){//ProcesarlarespuestaprocesarRespuestaEliminar(response);

    }},newResponse.ErrorListener(){@OverridepublicvoidonErrorResponse(VolleyErrorerror){Log.d(TAG,"ErrorVolley:"+error.getMessage());}}

    ){@OverridepublicMapgetHeaders(){Mapheaders=newHashMap();headers.put("ContentType","application/json;charset=utf8");headers.put("Accept","application/json");

  • returnheaders;}

    @OverridepublicStringgetBodyContentType(){return"application/json;charset=utf8"+getParamsEncoding();}});}

    /***Procesalarespuestadeeliminacinobtenidadesdeelsevidor*/privatevoidprocesarRespuestaEliminar(JSONObjectresponse){

    try{//ObtenerestadoStringestado=response.getString("estado");//ObtenermensajeStringmensaje=response.getString("mensaje");

    switch(estado){case"1"://MostrarmensajeToast.makeText(getActivity(),mensaje,Toast.LENGTH_LONG).show();//EnviarcdigodexitogetActivity().setResult(203);//TerminaractividadgetActivity().finish();break;

    case"2"://MostrarmensajeToast.makeText(getActivity(),mensaje,Toast.LENGTH_LONG).show();//EnviarcdigodefallagetActivity().setResult(Activity.RESULT_CANCELED);//TerminaractividadgetActivity().finish();break;}}catch(JSONExceptione){e.printStackTrace();}

    }

    /***Procesalarespuestadeactualizacinobtenidadesdeelsevidor*/privatevoidprocesarRespuestaActualizar(JSONObjectresponse){

    try{//ObtenerestadoStringestado=response.getString("estado");//ObtenermensajeStringmensaje=response.getString("mensaje");

    switch(estado){case"1"://MostrarmensajeToast.makeText(getActivity(),mensaje,Toast.LENGTH_LONG).show();//EnviarcdigodexitogetActivity().setResult(Activity.RESULT_OK);//TerminaractividadgetActivity().finish();break;

  • case"2"://MostrarmensajeToast.makeText(getActivity(),mensaje,Toast.LENGTH_LONG).show();//EnviarcdigodefallagetActivity().setResult(Activity.RESULT_CANCELED);//TerminaractividadgetActivity().finish();break;}}catch(JSONExceptione){e.printStackTrace();}

    }

    /***Actualizalafechadelcampo{@linkfecha_text}**@paramanoAo*@parammesMes*@paramdiaDa*/publicvoidactualizarFecha(intano,intmes,intdia){//Seteareneltextviewlafechafecha_text.setText(ano+""+(mes+1)+""+dia);}

    /***Muestraundilogodeconfirmacin,cuyomensajeesta*basadoenelparmetroidentificadordeStrings**@paramidParmetro*/privatevoidmostrarDialogo(intid){DialogFragmentdialogo=ConfirmDialogFragment.createInstance(getResources().getString(id));dialogo.show(getFragmentManager(),"ConfirmDialog");}

    }

    Este cdigo es un poco largo debido a que tenemos la implementacin de dilogos y comunicaciones de datos. Por lo que acontinuacin teexplico la esencia de las peticiones de informacin.

    Cargar los datos de la meta en los componentes del formulario:En el mtodo onCreateView() obtenemos el valor extra con que fue creado elfragmento. Si existe un valor extra, lanzamos la misma peticin que hemos usado para conseguir el detalle de la meta con el mtodocargarDatos() .

    Inmediatamente los datos conseguidos en la peticin, los seteamos en cada view del formulario.

    Manejar los eventos en cada action button: Para lograr esta tarea se implement el mtodo onOptionsItemSelected() , donde se cre unaestructura switch que permitiera la ejecucin del mtodo correspondiente a la accin. Recuerda usar onHasOptionMenu() en onCreate() paraque el fragmento pueda escuchar los eventos de la action bar.

    Implementar la insercin, eliminacin y borrado de las metas: Cada operacin en la base de datos tiene un mtodo asignado para surealizacin. Estos son: guardarMeta() y borrarMeta() .El primer mtodo realiza una peticin POST con la respectiva URL del servicio deactualizacin, usando los valores actuales del formulario.

    Similarmente borrarMeta() enva el id de la meta que se desea eliminar hacia la direccin correspondiente.

    En cuanto a los dilogos, simplemente usamos el formato clsico de ACEPTAR|CANCELAR para permitir o no el efecto de los mtodos en la basede datos. Puedes encontrar la implementacin completa descargando el cdigo en la parte superior del artculo.

    Paso #11: Realizar peticin para insertar nuevos registrosLa insercin de nuevas metas la crearemos en una nueva actividad llamada InsertActivity junto a un fragmento InsertFragment . Haremos

  • exactamente lo mismo que hemos venido haciendo.

    Iniciaremos el fragmento y estaremos a la espera de que el usuario guarde los datos o los descarte. Veamos:

    InsertActivity.java

    importandroid.os.Bundle;importandroid.support.v4.app.DialogFragment;importandroid.support.v7.app.AppCompatActivity;importandroid.view.Menu;

    importcom.herprogramacion.iwish.R;importcom.herprogramacion.iwish.ui.fragmentos.ConfirmDialogFragment;importcom.herprogramacion.iwish.ui.fragmentos.DatePickerFragment;importcom.herprogramacion.iwish.ui.fragmentos.InsertFragment;

    publicclassInsertActivityextendsAppCompatActivityimplementsDatePickerFragment.OnDateSelectedListener,ConfirmDialogFragment.ConfirmDialogListener{

    @OverrideprotectedvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);

    if(getSupportActionBar()!=null)getSupportActionBar().setHomeAsUpIndicator(R.mipmap.ic_done);

    //Creacindelfragmentodeinsercinif(savedInstanceState==null){getSupportFragmentManager().beginTransaction().add(R.id.container,newInsertFragment(),"InsertFragment").commit();}}

    @OverridepublicbooleanonCreateOptionsMenu(Menumenu){getMenuInflater().inflate(R.menu.menu_form,menu);returntrue;}

    @OverridepublicvoidonDateSelected(intyear,intmonth,intday){InsertFragmentinsertFragment=(InsertFragment)getSupportFragmentManager().findFragmentByTag("InsertFragment");

    if(insertFragment!=null){insertFragment.actualizarFecha(year,month,day);}}

    @OverridepublicvoidonDialogPositiveClick(DialogFragmentdialog){InsertFragmentinsertFragment=(InsertFragment)getSupportFragmentManager().findFragmentByTag("InsertFragment");

    if(insertFragment!=null){finish();//Finalizaractividaddescartandocambios}}

    @OverridepublicvoidonDialogNegativeClick(DialogFragmentdialog){InsertFragmentinsertFragment=(InsertFragment)getSupportFragmentManager().findFragmentByTag("InsertFragment");

    if(insertFragment!=null){//Nadaporelmomento}}}

  • Ahora el fragmento de insercin tiene las siguientes caractersticas:

    InsertFragment.java

    importandroid.app.Activity;importandroid.os.Bundle;importandroid.support.v4.app.DialogFragment;importandroid.support.v4.app.Fragment;importandroid.util.Log;importandroid.view.LayoutInflater;importandroid.view.Menu;importandroid.view.MenuInflater;importandroid.view.MenuItem;importandroid.view.View;importandroid.view.ViewGroup;importandroid.widget.EditText;importandroid.widget.Spinner;importandroid.widget.TextView;importandroid.widget.Toast;

    importcom.android.volley.Request;importcom.android.volley.Response;importcom.android.volley.VolleyError;importcom.android.volley.toolbox.JsonObjectRequest;importcom.herprogramacion.iwish.R;importcom.herprogramacion.iwish.tools.Constantes;importcom.herprogramacion.iwish.web.VolleySingleton;

    importorg.json.JSONException;importorg.json.JSONObject;

    importjava.util.HashMap;importjava.util.Map;

    /***Fragmentoquepermitealusuarioinsertarunnuevameta*/publicclassInsertFragmentextendsFragment{/***Etiquetaparadepuracin*/privatestaticfinalStringTAG=InsertFragment.class.getSimpleName();

    /*Controles*/EditTexttitulo_input;EditTextdescripcion_input;Spinnerprioridad_spinner;TextViewfecha_text;Spinnercategoria_spinner;

    publicInsertFragment(){}

    @OverridepublicvoidonCreate(BundlesavedInstanceState){super.onCreate(savedInstanceState);//HabilitaralfragmentoparacontribuirenlaactionbarsetHasOptionsMenu(true);}

    @OverridepublicViewonCreateView(LayoutInflaterinflater,ViewGroupcontainer,BundlesavedInstanceState){//InflandolayoutdelfragmentoViewv=inflater.inflate(R.layout.fragment_form,container,false);

    //Obtencindeinstanciascontrolestitulo_input=(EditText)v.findViewById(R.id.titulo_input);descripcion_input=(EditText)v.findViewById(R.id.descripcion_input);fecha_text=(TextView)v.findViewById(R.id.fecha_ejemplo_text);categoria_spinner=(Spinner)v.findViewById(R.id.categoria_spinner);prioridad_spinner=(Spinner)v.findViewById(R.id.prioridad_spinner);

  • fecha_text.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewv){DialogFragmentpicker=newDatePickerFragment();picker.show(getFragmentManager(),"datePicker");

    }});

    returnv;}

    @OverridepublicvoidonCreateOptionsMenu(Menumenu,MenuInflaterinflater){super.onCreateOptionsMenu(menu,inflater);//Removerelactionbuttondeborrarmenu.removeItem(R.id.action_delete);}

    @OverridepublicbooleanonOptionsItemSelected(MenuItemitem){intid=item.getItemId();

    switch(id){caseandroid.R.id.home://CONFIRMARif(!camposVacios())guardarMeta();elseToast.makeText(getActivity(),"Completaloscampos",Toast.LENGTH_LONG).show();returntrue;

    caseR.id.action_discard://DESCARTARif(!camposVacios())mostrarDialogo();elsegetActivity().finish();break;

    }

    returnsuper.onOptionsItemSelected(item);}

    /***Guardaloscambiosdeunametaeditada.**Siestenmodoinsercin,entoncescreaunanueva*metaenlabasededatos*/publicvoidguardarMeta(){

    //ObtenervaloresactualesdeloscontrolesfinalStringtitulo=titulo_input.getText().toString();finalStringdescripcion=descripcion_input.getText().toString();finalStringfecha=fecha_text.getText().toString();finalStringcategoria=categoria_spinner.getSelectedItem().toString();finalStringprioridad=prioridad_spinner.getSelectedItem().toString();

    HashMapmap=newHashMap();//Mapeoprevio

    map.put("titulo",titulo);map.put("descripcion",descripcion);map.put("fechaLim",fecha);map.put("categoria",categoria);map.put("prioridad",prioridad);

    //CrearnuevoobjetoJsonbasadoenelmapaJSONObjectjobject=newJSONObject(map);

    //DepurandoobjetoJson...Log.d(TAG,jobject.toString());

  • //ActualizardatosenelservidorVolleySingleton.getInstance(getActivity()).addToRequestQueue(newJsonObjectRequest(Request.Method.POST,Constantes.INSERT,jobject,newResponse.Listener(){@OverridepublicvoidonResponse(JSONObjectresponse){//ProcesarlarespuestadelservidorprocesarRespuesta(response);}},newResponse.ErrorListener(){@OverridepublicvoidonErrorResponse(VolleyErrorerror){Log.d(TAG,"ErrorVolley:"+error.getMessage());}}

    ){@OverridepublicMapgetHeaders(){Mapheaders=newHashMap();headers.put("ContentType","application/json;charset=utf8");headers.put("Accept","application/json");returnheaders;}

    @OverridepublicStringgetBodyContentType(){return"application/json;charset=utf8"+getParamsEncoding();}});

    }

    /***Procesalarespuestaobtenidadesdeelsevidor**@paramresponseObjetoJson*/privatevoidprocesarRespuesta(JSONObjectresponse){

    try{//ObtenerestadoStringestado=response.getString("estado");//ObtenermensajeStringmensaje=response.getString("mensaje");

    switch(estado){case"1"://MostrarmensajeToast.makeText(getActivity(),mensaje,Toast.LENGTH_LONG).show();//EnviarcdigodexitogetActivity().setResult(Activity.RESULT_OK);//TerminaractividadgetActivity().finish();break;

    case"2"://MostrarmensajeToast.makeText(getActivity(),mensaje,Toast.LENGTH_LONG).show();//EnviarcdigodefallagetActivity().setResult(Activity.RESULT_CANCELED);//TerminaractividadgetActivity().finish();break;}

  • }catch(JSONExceptione){e.printStackTrace();}

    }

    /***Validasiloscampos{@linktitulo_input}y{@linkdescripcion_input}*sehanrellenado**@returntruesialgunoodosdeloscamposestnvacios,falsesiambos*estncompletos*/publicbooleancamposVacios(){Stringtitulo=titulo_input.getText().toString();Stringdescripcion=descripcion_input.getText().toString();

    return(titulo.isEmpty()||descripcion.isEmpty());}

    /***Actualizalafechadelcampo{@linkfecha_text}**@paramanoAo*@parammesMes*@paramdiaDa*/publicvoidactualizarFecha(intano,intmes,intdia){//Seteareneltextviewlafechafecha_text.setText(ano+""+(mes+1)+""+dia);}

    /***Muestraundilogodeconfirmacin*/publicvoidmostrarDialogo(){DialogFragmentdialogo=ConfirmDialogFragment.createInstance(getResources().getString(R.string.dialog_discard_msg));dialogo.show(getFragmentManager(),"ConfirmDialog");}

    }

    Esta vez hemos creado un mtodo llamado guardarMeta() basado en la URL del servicio de insercin y los datos que el usuario hayacompletado. Si te fijas en el procesamiento de los eventos sobre la action bar, puedes ver que existe la posibilidad de guardar y descartar losdatos.

    Ambos se basan en la validacin de los campos del formulario que requieren texto escrito por parte del usuario. Para ello se cre el mtodocamposVacios() . Dependiendo de su retorno as mismo procederemos.

    Esto quiere decir que el usuario no puede guardar una meta sin completar alguno de los campos. Ni tampoco puede intentar descartarcambios sin ver un dilogo si ya ha escrito algn dato.

    Ejecutar Proyecto Completo En Android StudioRecuerda que puedes descargar el proyecto completo con el botn que tienes en el inicio del articulo. Al final, luego de haber seguido todos lospasos la aplicacin se ver as:

  • ConclusionesUsar un Web Service en Php permite compartir datos entre tus aplicativos externos y tus aplicaciones android para mantener un proyectointegral. Sin embargo el uso de un estilo de comunicacin elegante como REST es un excelente complemento para estructurar una buena API.

    Json es un formato muy flexible y cmodo a la vista. Esto lo hace un excelente complemento para implementaruna API entre Android, Mysql yPhp.

    Aade caching de informacin a travs de SQLite para evitar realizar gran cantidad de operaciones de red.

    Usa la clase ContentProvider para completar tu patrn MVC de Red y aadir restricciones RESTful en tu aplicacin. Esto te permitirindependizar tus clases y evitar problemas en tu hilo principal de forma sencilla.