viernes, 9 de mayo de 2014

WebService: Conexión a base de datos Mysql desde Android. PARTE 2.(Mostrar)

Buenas amigos, en este nuevo tema vamos a continuar hablando de como conectar nuestra aplicación android a nuestro servidor Mysql. En el tema anterior, la PARTE 1, estuvimos viendo como insertar datos en nuestra base de datos, en este tema veremos como recuperar esos datos y mostrarlos en nuestro dispositivo.



Bien, deciros que no voy a utilizar JSON para obtener los datos, si no que crearé una clase Personas donde iré almacenando los datos de cada persona, para posteriormente guardar ese objeto "Persona" en un ArrayList. Esta forma de hacerlo quizás no sea la más correcta, pero es suficientemente válida como para explicarla. La forma correcta sería utilizando JSON, pero no quiero complicar más el tema.

Empecemos, aquí os dejo la clase, el archivo .xml y el webservice de la PARTE 1, por si no lo tenéis:

WebSeviceExample

Bien, lo primero que haremos será agregar una nueva clase Personas, la cual tendrá como atributos:

    • Nombre
    • DNI
    • Telefono
    • Email


Una vez la tengamos creada, nos vamos a nuestra clase y creamos nuevos atributos que vamos a utilizar:
  • private int posicion=0;
  • private List listaPersonas;
    • Esta lista la iniciamos en el método onCretae():
      • listaPersonas=new ArrayList();

Posteriormente creamos un método para obtener los datos del WebService:


Veamos, este código cambia ligeramente con respecto al método insertar que creamos en la PARTE 1.
  • Este método es de tipo String, por lo tanto nos devolverá una String con los resultados obtenidos de nuestro servidor.
  • Creamos una variable local de tipo String llamada resquest, esta almacenará la respuesta.
    • String resquest="";
  • Instanciamos HttpClient y HttpPost para comunicarnos con nuestro Webservice.
    • HttpClient httpclient=new DefaultHttpClient();
    • HttpPost httppost=new HttpPost("URL DE NUESTRO WEBSERVICE EN EL SERVIDOR");
  • Con respecto a nuestro método "ingresar", no vamos a crear un ArrayList para almacenar datos y pasárselos al servidor, ya que es el servidor el que nos tiene que pasar los datos.
  • Tampoco vamos codificar datos, ya que no tenemos datos que codificar.
  • Creamos un objeto de la clase ResponseHandler, ya que para que nos de una respuesta el webservice debemos de pasarle este handler al método excute() de HttpClient por parámetro para que nos devuelva los datos.
    • ResponseHandler responseHandler=new BasicResponseHandler();
  • Le decimos a HttpClient que ejecute la petición a nuestro webservice, y este nos devolverá una String, la cual almacenamos en resquest:
    • resquest=httpclient.execute(httppost, responseHandler);
Bien, ya tenemos el código para obtener los datos del servidor, veamos que es lo que hace nuestro Webservice cuando conectamos con él.:


Como podéis observar, cambia poco con respecto a nuestro WebService "insert.php":
  • Lo primero es meter la información de nuestro servidor:
    • Hostname: Nombre del host.
    • Database: Nombre de nuestra base de datos.
    • Username: Nombre de usuario del servidor.
    • Password: Contraseña del servidor.
  • Posteriormente nuestro WebService intentará conectar al servidor, enviando un informe de error en caso de no porder conectar:
    •  $localhost=mysql_connect($hostname_localhost,$username_localhost,$password_localhost)
    • or trigger_error(mysql_error(),E_USER_ERROR);
  • Una vez conectado al servidor, intentará conectar con nuestra base de datos
    • mysql_select_db($database_localhost, $localhost);
  • Luego, creamos una sentencia sql para que obtenga todos los datos del servidor.
    • $query_search = "select * from personas order by dni";
  • Ejecuta la sentencia sql:
    • $query_exec = mysql_query($query_search) or die(mysql_error());
  • Finalmente, y mediante un bucle WHILE nos irá imprimiendo los resultados.
    • while($row = mysql_fetch_array($query_exec)){
    • echo $row['nombre']."
      ".$row['dni']."
      ".$row['telefono']."
      ".$row['email']."/";
    • }
  • Cerramos la conexión:
    • mysql_close($localhost);
Decir que la barra al final del echo "/" y los "br", los pongo para filtrar y descomponer la información que me envía el servidor, ya que este me manda una String con todas las filas, y yo las filtro para poder manejar los datos individualmente.

Bien, ya sabemos como funciona nuestro WebService y tenemos almacenada la información del servidor, ahora vamos a crear un método que nos filtre los resultados y nos lo almacene en objetos:


Veamos:
  • Creamos un método booleano que en caso de no obtener resultados de nuestro WebService retornará false y en caso de obtener resultados, lo descompondrá, lo almacenará y retornará true.
  • Limpiamos nuestro ArrayList por si tuviese algo de información.
    • listaPersonas.clear();
  • Ahora creamos una condición if para comprobar que nuestro resultado contiene información para poder continuar.
    • if(!mostrar().equalsIgnoreCase(""))
  • Si la condición es cierta, pasamos el primer filtro separando la información por bloques utilizando como elemento separatorio la barra "/"
    • String [] cargaDatos=mostrar().split("/");
      • Acordaos de que nuestro webservice imprimía una barra "/" cada vez que mostraba una fila, es la que utilizo para el split.
  • Tenemos las filas almacenadas en un array, pero cada posición del array almacena una String con todos los datos de la persona, por lo tanto le vamos a pasar un segundo filtro para almacenar finalmente los datos de forma individual.
    • Creamos un for que recorra nuestro array "cargaDatos".
      • for (int i = 0; i < cargarDatos.length; i++) {
    • Por cada posición del array lo descomponemos con otro split, en este caso utilizaremos br para nuestro split.
      • String datosPersona[]=cargarDatos[i].split("<"br">");
        • quitarle las comillas a "br", que es que si no me crea un conflicto con el html y me genera un salto de linea
    • Creamos un objeto de la clase Personas
      • Perosnas personas=new Personas();
    • Le damos a cada atributo de personas el valor almacenado en nuestro array "datosPersonas"
      • personas.setNombre(datosPersona[0]);
      • personas.setDni(datosPersona[1]);
      • personas.setTelefono(datosPersona[2]);
      • personas.setEmail(datosPersona[3]);
    • Finalmente agregamos nuestro objeto Personas a nuestro ArrayList:
      • listaPersonas.add(personas);
Antes de pasar a nuestro AsyncTask para cargar los datos, vamos a crear otro método que nos imprima en nuestro formulario los datos almacenados en nuestro ArrayList.


Este método no tiene mucha historia, le pasamos una posición por parámetro y, corriendo en un hilo, nos busca el objeto almacenado en la posición indicada y lo muestra en nuestro formulario.

Finalmente lo ejecutamos todo en nuestro AsyncTask:

 Ya con todo, nos vamos a nuestro botón mostrar y le damos una acción:

Para darle un poco más de chicha creamos los ImageButton "mas" y "menos", la acción de estos botones sería:


La acción de "mas" sería:
  • Comprobar que la lista no este vacía
    • if(!listaPersonas.isEmpty)
  • Si no esta vacía comprueba que la variable int posicion no tenga un valor superior al tamaño de nuestro ArrayList
    • if(posicion>=listaPersonas.size()-1)
  • Si es superior o igual, iguala el valor de posicion al tamaño de nuestro ArrayList y muestra el objeto, en nuestro formulario, de dicha posición.
    • posicion=listaPersonas.size()-1;
    • mostrarPersona(posicion)
  • Si no es superior o igual, suma +1 al valor de posicion y muestra los resultados en nuestro formulario:
    • posicion++;
    • mostrarPersona(posicion);
La acción de nuestro botón "menos" es muy parecida:

Bien, es mu parecido al funcionamiento de nuestro botón "mas" así que supongo que no necesite una explicación.

Bien amigos, hasta aquí la PARTE 2, espero no haberos hecho un cacao mental, y haberme expresado con claridad

Os dejo el link con el WebService "selectAll.php" y la clase con todos los métodos.


Continuaremos con la PARTE 3

PD: Decir, una vez más, que esta forma de hacerlo no sea la más correcta, pero es valida, ya que no vulnero la seguridad en ningún momento (Certificados SSL y encriptación en los próximos temas), aunque si es verdad que no he tenido cuidado a la hora de optimizar la memoria que consume por lo poca cosa que es, pero ya os digo, que consume mucho para la poca cosa que es, pero lo he hecho así aún sabiéndolo, porque no me quería entretener con esto mucho tiempo. La optimización de memoria corre por vuestra cuenta :P

Un saludo a todos.

31 comentarios:

  1. hola amigo, muy buenos tus tutoriales, me han servido mucho !!
    tengo una duda si con el funcionamiento de este, en que momento seteas los campos del main_activy ?? :/ lo que pasa es que no me muestra nada en la pantalla al momento de presionar el boton mostrar, solo me funciona el ingresar hasta ahora, cuando presiono el boton mostrar se cierra la aplicacion :(

    saludos!

    ResponderEliminar
    Respuestas
    1. Buenas Daniel, vas a tener que pasarme el log que te lanza Android cuando te falla, ya que puede ser por varios motivos:

      *Error de código
      *Error de Servidor
      *Cortafuegos o antivirus (Algún caso he tenido)

      Un saludo y envíame el log para poder ayudarte.

      Eliminar
    2. A mi me pasa lo mismo solo anda el Insert.
      El Log dice lo siguiente:
      10-28 12:54:20.808: E/AndroidRuntime(527): FATAL EXCEPTION: AsyncTask #4
      10-28 12:54:20.808: E/AndroidRuntime(527): java.lang.RuntimeException: An error occured while executing doInBackground()
      10-28 12:54:20.808: E/AndroidRuntime(527): at android.os.AsyncTask$3.done(AsyncTask.java:200)
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.util.concurrent.FutureTask.run(FutureTask.java:137)
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.lang.Thread.run(Thread.java:1096)
      10-28 12:54:20.808: E/AndroidRuntime(527): Caused by: java.lang.IllegalArgumentException: Illegal character in scheme at index 0: 10.10.220.80:8081/BaseAndroid/delete.php
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.net.URI.create(URI.java:970)
      10-28 12:54:20.808: E/AndroidRuntime(527): at org.apache.http.client.methods.HttpPost.(HttpPost.java:79)
      10-28 12:54:20.808: E/AndroidRuntime(527): at com.example.proyectobase.WebServiceExample.eliminar(WebServiceExample.java:272)
      10-28 12:54:20.808: E/AndroidRuntime(527): at com.example.proyectobase.WebServiceExample.access$10(WebServiceExample.java:267)
      10-28 12:54:20.808: E/AndroidRuntime(527): at com.example.proyectobase.WebServiceExample$Delete.doInBackground(WebServiceExample.java:418)
      10-28 12:54:20.808: E/AndroidRuntime(527): at com.example.proyectobase.WebServiceExample$Delete.doInBackground(WebServiceExample.java:1)
      10-28 12:54:20.808: E/AndroidRuntime(527): at android.os.AsyncTask$2.call(AsyncTask.java:185)
      10-28 12:54:20.808: E/AndroidRuntime(527): at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
      10-28 12:54:20.808: E/AndroidRuntime(527): ... 4 more
      10-28 12:54:20.978: W/IInputConnectionWrapper(527): showStatusIcon on inactive InputConnection

      Eliminar
  2. Amigo hazla con el metodo JSON te lo agradezco.

    ResponderEliminar
    Respuestas
    1. Amigo y como hago para optimizar lo de la memoria, regalame un consejo por favor.

      Eliminar
    2. Este comentario ha sido eliminado por el autor.

      Eliminar
  3. seria mas que genial lo hicieras con JSON, saludos y muchas gracias

    ResponderEliminar
    Respuestas
    1. Buenas, para mostrar los resultados en tu app por medio de JSON visita este enlace:

      http://picarcodigo.blogspot.com.es/2014/06/webservice-obtener-datos-mysql-desde.html

      Eliminar
  4. Muy buenos tutoriales me han servido bastante, en mostrar me esta generabdo un error te muestro el log


    12-06 11:59:34.130 2370-2390/tes.schooltato.com.conectarmysql E/AndroidRuntime﹕ FATAL EXCEPTION: AsyncTask #1
    Process: tes.schooltato.com.conectarmysql, PID: 2370
    java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:300)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:355)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:222)
    at java.util.concurrent.FutureTask.run(FutureTask.java:242)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
    at java.lang.Thread.run(Thread.java:818)
    Caused by: java.lang.ArrayIndexOutOfBoundsException: length=3; index=3
    at tes.schooltato.com.conectarmysql.MainActivity.filtrarDatos(MainActivity.java:239)
    at tes.schooltato.com.conectarmysql.MainActivity.access$1000(MainActivity.java:31)
    at tes.schooltato.com.conectarmysql.MainActivity$Mostrar.doInBackground(MainActivity.java:317)
    at tes.schooltato.com.conectarmysql.MainActivity$Mostrar.doInBackground(MainActivity.java:313)
    at android.os.AsyncTask$2.call(AsyncTask.java:288)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
                at java.lang.Thread.run(Thread.java:818)

    lo raro es que me estaba funcionando pero cuando implemente el update me empeso a salir este error.
    de ante mano gracias por tu colaboracion.

    ResponderEliminar
    Respuestas
    1. les quería comentar cual era el inconveniente que tenia con el error anterior, esto se presenta cuando un dato de algunos de los registros que se están consultando esta vació.

      Eliminar
    2. y como se resuelve?

      Eliminar
    3. Buenas, para resolver este inconveniente puedes hacer varias cosas:

      1: No dejar que entren campos vacios comprobando las variables que le mandas a la tabla y si hay algún valor null que te escriba "vacio".
      2: Comprobar los valores que te vienen de la tabla y comprobar si hay algún valor null, y si es así cambiarlo por algo como "campo vacio" o simplemente si no se quiere poner nada poner dobles comillas a la variable tipo String.

      Con eso podrías solucionar el tema de los valores null.

      De todas maneras el error que le tiraba a Javier es que intentaba meter más datos en el array de los que tenía declarados.

      Caused by: java.lang.ArrayIndexOutOfBoundsException: length=3; index=3 esta linea de su error lo dice.

      Un saludo.

      Eliminar
    4. Este comentario ha sido eliminado por el autor.

      Eliminar
    5. Este comentario ha sido eliminado por el autor.

      Eliminar
    6. lo que pasa es que tu archivo php esta botando seguro un error de advertencia es minimo por cuestion de versiones de php pero ese error antes tira un espacio (etiqueta br "'
      '")
      el cual te genera un espacion en blanco lo que hice fue agregar esta linea de codigo
      error_reporting(E_ALL ^ E_DEPRECATED);
      despues de la etiqueta
      <?php
      y lesto elimina el error de advertencia, espero les sirva y pues fue un poco tarde la respuesta pero me sirivio xD saludos muy buen tuto

      Eliminar
    7. Tengo el error Caused by: java.lang.ArrayIndexOutOfBoundsException: length=1; index=1 pero no se como resolverlo. Alguien me da una mano?

      Eliminar
    8. El problema lo estoy teniendo en el webservice selectAll.php ... pero no entiendo como solucionarlo

      Eliminar
    9. que tal matias si te resolvieron tu duda ???

      Eliminar
  5. Mi proyecto final de xiu depende de que encuentre la tercera parte de este tutorial. alguien seria tan amable de indicarme donde carajo esta?

    ResponderEliminar
    Respuestas
    1. Aqui: http://picarcodigo.blogspot.com.es/2014/05/webservice-conexiones-mysql-desde.html

      Eliminar
  6. Gracias me funciono de maravilla esto es lo unico que cambie:

    Personas personas= (Personas) listaPersonas.get(posicion);

    ResponderEliminar
    Respuestas
    1. a mi tambien me tira error ahi y el entorno me dice que castee, asi como lo hiciste vos... pero al ejecutar la app me tira error... nose porque :/

      Eliminar
  7. Si copio el codigo tal cual esta, me tira error en la linea "Personas personas = listaPersonas.get(posicion);" del metodo mostrarPersona, lo que el entorno me propone castear al paquete de la clase.
    Pero si hago el cast al ejecutar me tira error en doInBackground, que puede ser?

    ResponderEliminar
  8. HOLA!. El tuto está muy bueno, pero me gustaría saber con que programa y version hiciste la APP ya que en android Studio no me salen varias opciones que describes en el tutorial, como por ejemplo la conexion a la base de datos con las opciones "HttpClient y Post"..

    Desde ya muchas gracias!

    Un saludo

    ResponderEliminar
    Respuestas
    1. Buenas, para usar HTTPClient y Post, tenes que agregar las dependencias en el gradle de apache!

      Eliminar
  9. Hola, estoy usando Java para mí web service, pero uso la url de mi wsdl y no puede hacer el insert, me podrías ayudar?

    ResponderEliminar
  10. Buen día

    ayuda tengo este problema voy a buscar un usuario

    Gracias a quien pueda

    10-26 22:14:23.455 30642-16605/com.mike.android.unibank W/dalvikvm: threadid=13: thread exiting with uncaught exception (group=0xa6205908)
    10-26 22:14:23.455 30642-16605/com.mike.android.unibank E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #3
    java.lang.RuntimeException: An error occured while executing doInBackground()
    at android.os.AsyncTask$3.done(AsyncTask.java:299)
    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352)
    at java.util.concurrent.FutureTask.setException(FutureTask.java:219)
    at java.util.concurrent.FutureTask.run(FutureTask.java:239)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
    at java.lang.Thread.run(Thread.java:856)
    Caused by: java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
    at com.mike.android.unibank.Actualizar_Usuario.filtrarDatos(Actualizar_Usuario.java:133)
    at com.mike.android.unibank.Actualizar_Usuario.access$600(Actualizar_Usuario.java:27)
    at com.mike.android.unibank.Actualizar_Usuario$Mostrar.doInBackground(Actualizar_Usuario.java:166)
    at com.mike.android.unibank.Actualizar_Usuario$Mostrar.doInBackground(Actualizar_Usuario.java:162)
    at android.os.AsyncTask$2.call(AsyncTask.java:287)
    at java.util.concurrent.FutureTask.run(FutureTask.java:234)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) 
    at java.lang.Thread.run(Thread.java:856) 

    ResponderEliminar
    Respuestas
    1. A mi me tiraba un error parecido, tenés que inicializar la lista!

      Eliminar
  11. En mi base de datos no hay campos vacios; asi la tengo
    id nombre apellido correo telefono username pass reppass
    12 Jairo Alberto Moncada jairo529@gmail.com 123456 jairo jairo jairo

    ResponderEliminar
  12. exelente tutorial
    una consulta muy importante ..... es necesario poner la dirección ip para hacer solicitudes usando httppost ?porque cuando pongo en ves de mi ip el localhost no me aparece nada ya deja de comunicarse con la base de datos ..
    httppost= new HttpPost("http://10.127.127.1/webservice/mostrar.php"); // aka se comunica
    httppost= new HttpPost("http://localhost/webservice/mostrar.php"); // aka ya no nada

    ResponderEliminar