Crear y Leer JSON desde Android

Blog >Comunicación con servidor > parseando con JSON en Android


Hola developers, vamos a ver como se parsea un documento JSON en Android.



JSON EN ANDROID

JSON (JavaScript Object Notation) es un formato para intercambiar datos, JSON los describe con una sintaxis dedicada que se usa para identificarlos y gestionarlos. 

JSON es una alternativa a XML,y el fácil uso en javascript ha generado un gran numero de seguidores. Una de las mayores ventajas que tiene el uso de JSON es que puede ser leído por cualquier lenguaje de programación. Así que en resumen, puede ser usado para el intercambio de información entre tecnologías distintas.

Según esté realizado el formulario, nos encontraremos con arrays u objetos, y así lo representaremos en el código.






Por ejemplo tenemos este código en JSON, hay herramientas online para la visualización de nuestro archivo JSON y para que se nos ayude con la sintaxis, como por ejemplo JSON Viewer

{
    "Personajes": [
        {
                "Equipo": "Elfos",
                "name": "Arwen",
                "Especialidad":"guerrero",
                "image": "http://oi60.tinypic.com/2emoi7n.jpg",
                "Habilidades": {
                    "Fuerza": "7",
                    "Espiritu": "2",
                    "Fortaleza": "8"
                }
        },
       {
                "Equipo": "Orcos",
                "name": "Arwen",
                "Especialidad":"Brujo",
                "image": "http://oi59.tinypic.com/2jetzl0.jpg",
                "Habilidades": {
                    "Fuerza": "1",
                    "Espiritu": "10",
                    "Fortaleza": "5"
                }
        },
        {
                "Equipo": "Humanos",
                "name": "Arwen",
                "Especialidad":"Mago",
                "image": "http://oi61.tinypic.com/msoyfa.jpg",
                "Habilidades": {
                    "Fuerza": "1",
                    "Espiritu": "9",
                    "Fortaleza": "3"
                }
        }
  ]
}

Este archivo le podeis descargar desde aquí.

Comenzamos por subir el archivo con extension JSON, en este caso lo llamaremos "Archivo.json". Para hacer la prueba, lo subí a dropbox, pero no os olvideis de cambiar las 3 www del enlace que conseguireis, por dl para tener el acceso público, de todas formas podreis ver el ejemplo en una de las clases.

Como profesionales que somos, he usado dropbox para el ejemplo, pero los programadores debemos huir literalmente de lo "gratis", lo que no se paga, tiene una seguridad endeble, entre otras desventajas. 

También he subido estas imágenes a un servidor gratuito TinyPic, quiere decir que podeis usar el mismo archivo JSON que yo.

IMAGENES
Orco


Elfo



humano



Importamos estas librerías al proyecto para poder usar JSON :


Tendremos que guardar los datos en una clase JavaBeans, así que creamos la correspondiente a nuestro archivo JSON para trabajar y gestionar los objetos :

public class Personajes {

 private String nombre;
 private String profesion;
 private String equipo;
 private String Fuerza;
 private String Fortaleza;
 private String Espiritu;
 private String URLimagen;
 public Bitmap imagen;
 


 public Personajes() {
  super();
 }
 
 public String getEquipo() {
  return equipo;
 }
 public void setEquipo(String equipo) {
  this.equipo = equipo;
 }

 public String getNombre() {
  return nombre;
 }
 public void setNombre(String nombre) {
  this.nombre = nombre;
 }
 public String getProfesion() {
  return profesion;
 }
 public void setProfesion(String profesion) {
  this.profesion = profesion;
 }
 
 public String getFuerza() {
  return Fuerza;
 }
 public void setFuerza(String fuerza) {
  Fuerza = fuerza;
 }
 public String getFortaleza() {
  return Fortaleza;
 }
 public void setFortaleza(String fortaleza) {
  Fortaleza = fortaleza;
 }
 public String getEspiritu() {
  return Espiritu;
 }
 public void setEspiritu(String espiritu) {
  Espiritu = espiritu;
 }
 public String getURLimagen() {
  return URLimagen;
 }

 public void setURLimagen(String uRLimagen) {
  URLimagen = uRLimagen;
 }
 public Bitmap getImagen() {
  // TODO Auto-generated method stub
  return imagen;
 }
}


Ahora vamos con el código, pongo a continuación las dos partes del main :


Y este es el código Java de momento :

public class MainActivity extends Activity {

 private Button buscar;
 private ListView listaa;
 String searchTerm ;
 //SI OS FIJAIS LA URL EMPIEZA POR dl EN VEZ DE www
 String URL = "https://dl.dropbox.com/s/sjhj5zuxfu87vz5/Archivo.json?dl=0";
 
 Activity a;
 Context context;
 static ArrayList lista;
 JSONArray pers;

 @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lista = new ArrayList();
        a=this;
        context=getApplicationContext();
        listaa = (ListView) findViewById(R.id.listViewLista);
        buscar = (Button) findViewById(R.id.busqueda);
        //VEMOS QUE HAY EN EL EDITTEXT
     buscar.setOnClickListener(new OnClickListener(){
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    //AQUI ES LA EJECUCIÓN DEL PARSEO DEL XML
   }     
     });
     
 }
}



A continuación tenemos el método público que utilizaremos para leer nuestro archivo JSON. Este método crea la llamada al servicio web. No os olvideis de darle permisos de internet a la aplicación.


//CLASE PARA RECOJER EL CODIGO EN BRUTO DEL JSON
public class JSONParser {

   static String response = null;
   public final static int GET = 1;
   public final static int POST = 2;
   //CONSTRUCTOR
   public JSONParser() {
   }
   
   public String makeServiceCall(String url, int method) {
       return this.makeServiceCall(url, method, null);
   }
   //METODO PARA ESTABLECER CONEXIÓN
   public String makeServiceCall(String url, int method,List params) {
       try {
           //HTTP CLIENT
           DefaultHttpClient httpClient = new DefaultHttpClient();
           HttpEntity httpEntity = null;
           HttpResponse httpResponse = null;
            
           // AÑADIMOS PARAMETROS AL METODO POST
           if (method == POST) {
               HttpPost httpPost = new HttpPost(url);
               // adding post params
               if (params != null) {
                   httpPost.setEntity(new UrlEncodedFormEntity(params));
               }
               httpResponse = httpClient.execute(httpPost);
           } else if (method == GET) {
               // AÑADIMOS PARAMETROS AL METODO GET
               if (params != null) {
                   String paramString = URLEncodedUtils.format(params, "utf-8");
                   url += "?" + paramString;
               }
               //METODO GET
               HttpGet httpGet = new HttpGet(url);
               httpResponse = httpClient.execute(httpGet);

           }
           httpEntity = httpResponse.getEntity();
           response = EntityUtils.toString(httpEntity);
           //EXCEPCIONES
       } catch (UnsupportedEncodingException e) {
           e.printStackTrace();
       } catch (ClientProtocolException e) {
           e.printStackTrace();
       } catch (IOException e) {
           e.printStackTrace();
       }
       //DEVOLVEMOS RESPUESTA
        return response;
   }
}


Vamos a completar nuestro main con 2 clases que harán la función de hilos, uno es para cargar los datos del objeto JSON en un ArrayList y otro es para cargar los datos correspondientes en el ListView, están enlazados y el código está bastante explicado e intuitivo.

//HILO PARA CARGAR LOS DATOS DEL JSON EN UN ARRAYLIST
class GetContacts extends AsyncTask {
   ListView list;
        private ProgressDialog pDialog;
     //CONSTRUCTOR
        public GetContacts(ListView listaa) {
   this.list=listaa;
  }
     
  @Override
     protected void onPreExecute() {
             super.onPreExecute();
             pDialog = new ProgressDialog(MainActivity.this);
             pDialog.setMessage("Getting Data ...");
             pDialog.setIndeterminate(false);
             pDialog.setCancelable(true);
             pDialog.show();
       }
 
        @Override
        protected Void doInBackground(Void... arg0) {
            // CREAMOS LA INSTANCIA DE LA CLASE
            JSONParser sh = new JSONParser();
            String jsonStr = sh.makeServiceCall(URL, JSONParser.GET);
            
            if (jsonStr != null) {
                try {
                    JSONObject jsonObj = new JSONObject(jsonStr);
                    // Getting JSON Array node
                    pers = jsonObj.getJSONArray("Personajes");
 
                    // looping through All Equipos
                    for (int i = 0; i < pers.length(); i++) {
                        JSONObject c = pers.getJSONObject(i);
                        //RECOJEMOS DATOS EN VARIABLES
                        String equipo = c.getString("Equipo");
                        String name = c.getString("name");
                        String especialidad = c.getString("Especialidad");
                        String imagen = c.getString("image");
      
                        //SUBITEM CON LAS HABILIDADES
                        JSONObject habilidades = c.getJSONObject("Habilidades");
                        String fuerza = habilidades.getString("Fuerza");
                        String espiritu = habilidades.getString("Espiritu");
                        String fortaleza = habilidades.getString("Fortaleza");
 
      //CREAMOS OBJETO Y LO LLENAMOS
                        Personajes e=new Personajes();
                        e.setURLimagen(imagen);
                        e.setNombre(name);
                        e.setEquipo(equipo);
                        e.setProfesion(especialidad);
                        e.setEspiritu(espiritu);
                        e.setFortaleza(fortaleza);
                        e.setFuerza(fuerza);
                        // adding contact to contact list
                        lista.add(e);
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            } else {
                Log.e("ServiceHandler", "Esta habiendo problemas para cargar el JSON");
            }
 
            return null;
        }
 
        @Override
        protected void onPostExecute(Void result) {
            super.onPostExecute(result);
            // Dismiss the progress dialog
            if (pDialog.isShowing()){
                pDialog.dismiss();
         }
         new CargarListTask().execute();
    }
//HILO PARA CARGAR LOS DATOS EN EL LISTVIEW
class CargarListTask extends AsyncTask{
     @Override
     protected void onPreExecute() {
         // TODO Auto-generated method stub
         super.onPreExecute();
     }
     protected Adapter doInBackground(Void... arg0) {
         // TODO Auto-generated method stub
         try{
         }catch(Exception ex){
             ex.printStackTrace();
         }
   
         Adapter adaptador = new Adapter(a,lista);
         return adaptador;
     }
     @Override
     protected void onPostExecute(Adapter result) {
         // TODO Auto-generated method stub
         super.onPostExecute(result);
         listaa.setAdapter(result);
     }
 }
 }



Si colocamos cuando clickamos el botón...

new GetContacts(listaa).execute();

Ya está!! sólo necesitamos un adapter con un hilo, este hilo se encargará de llenar la imágen a partir de la URL de la imagen, de esas 3 que he puesto al principio :

public class Adapter extends BaseAdapter{
   
    protected Activity activity;
    //ARRAYLIST CON TODOS LOS ITEMS
    protected ArrayList items;
     
    //CONSTRUCTOR
    public Adapter(Activity activity, ArrayList items) {
        this.activity = activity;
        this.items = items;
      }
    //CUENTA LOS ELEMENTOS
    @Override
    public int getCount() {
        return items.size();
    }
    //DEVUELVE UN OBJETO DE UNA DETERMINADA POSICION
    @Override
    public Object getItem(int arg0) {
        return items.get(arg0);
    }

    //METODO PRINCIPAL, AQUI SE LLENAN LOS DATOS
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // SE GENERA UN CONVERTVIEW POR MOTIVOS DE EFICIENCIA DE MEMORIA
     //ES UN NIVEL MAS BAJO DE VISTA, PARA QUE OCUPEN MENOS MEMORIA LAS
 
        View v = convertView;
        //ASOCIAMOS LA VISTA AL LAYOUT DEL RECURSO XML DONDE ESTA LA BASE DE
 
       if(convertView == null){
            LayoutInflater inf = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = inf.inflate(R.layout.list_item, null);
        }
  
        Personajes dir = items.get(position);
        //RELLENAMOS LA IMAGEN Y EL TEXTO
        //IMAGEN
        ImageView img = (ImageView) v.findViewById(R.id.imageView1);
  if(img != null) {
   new LoadImage(img).execute(dir.getURLimagen());
  }
        //CAMPOS
        TextView nombre = (TextView) v.findViewById(R.id.username);
        nombre.setText("NOMBRE : "+dir.getNombre());
        TextView clase = (TextView) v.findViewById(R.id.clase);
        clase.setText("PROFESION : "+dir.getProfesion());
        TextView equipo = (TextView) v.findViewById(R.id.equipo);
        equipo.setText("EQUIPO : "+dir.getEquipo());
        TextView fuerza = (TextView) v.findViewById(R.id.fuerza);
        //SUBCAMPOS
        fuerza.setText("FUERZA : "+dir.getFuerza());
        TextView fortaleza = (TextView) v.findViewById(R.id.fortaleza);
        fortaleza.setText("FORTALEZA : "+dir.getFortaleza());
        TextView espiritu = (TextView) v.findViewById(R.id.espiritu);
        espiritu.setText("ESPIRITU : "+dir.getEspiritu());
         
        // DEVOLVEMOS VISTA
        return v;
    }
 @Override
 public long getItemId(int position) {
  // TODO Auto-generated method stub
  return 0;
 }
 
 class LoadImage extends AsyncTask {
  ImageView bmImage;

  public LoadImage(ImageView bmImage) {
   this.bmImage = bmImage;
  }

  @Override
  protected Bitmap doInBackground(String... urls) {
   String urldisplay = urls[0];
   Bitmap mIcon11 = null;
   try {
    mIcon11 = BitmapFactory.decodeStream((InputStream)new URL(urldisplay).getContent());
     
   } catch (Exception e) {
    //Log.e("Error", e.getMessage());
    e.printStackTrace();
   }
   return mIcon11;
  }

  @Override
  protected void onPostExecute(Bitmap result) {
   bmImage.setImageBitmap(result);
  }
 }
}


Y por último el item_list....







Podeis descargar el código fuente de thebestandroide con sólo compartir en facebook,twitter,linkedin o suscribirte a nuestro canal RSS más abajo. 



Compartir Compartir Compartir Compartir



31 comentarios:

  1. Buenas, tengo una duda, tu codigo me funciona correctamente, pero cuando utilizo mi JSON que esta en un host gratuito al ejecutarlo no me sale nada en mi avd, si me pudieras ayudar, no entra en doInBackground directamente sale "Esta habiendo...."

    Muchas gracias

    ResponderEliminar
    Respuestas
    1. Buenas! Mira puede ser por dos cosas :
      -Por ejemplo en dropbox que es un servidor gratuito, para hacer el archivo público hay que cambiar las www por dl en la ruta que le metes a la clase java para leer el JSON.

      -Otra causa y las más probable, es que hayas cambiado la extuctura del JSON adaptandolo a tus necesidades y ahí este el jaleo. No obstante, si me pudieras poner el link de tu JSON y echarlo un ojo, te podría ayudar mejor.

      Saludos

      Eliminar
    2. Gracias por responder tan rápido, parece que puede ser un problema de convertir JsonArray a JsonObject, es uno de los warning que me da, ya que no me muestra los datos, sin embargo en el LogCat si que veo que aparecen.

      Te envio el enlace:
      http://www.bdmacotera.besaba.com/bdMacoteraConecta/db.php

      Si necesitas el codigo es este:

      $id, 'nombre'=> $nombre, 'telefono'=> $telefono, 'direccion'=> $direccion,
      'horario'=> $horario);
      }

      //desconectamos la base de datos
      $close = mysqli_close($conexion)
      or die("Ha sucedido un error inexperado en la desconexion de la base de datos");

      //Creamos el JSON
      $json_string = json_encode($organismos, JSON_FORCE_OBJECT);
      echo $json_string;

      //Si queremos crear un archivo json, sería de esta forma:
      /*
      $file = 'organismos.json';
      file_put_contents($file, $json_string);
      */

      ?>

      Eliminar
    3. $id, 'nombre'=> $nombre, 'telefono'=> $telefono, 'direccion'=> $direccion,
      'horario'=> $horario);
      }

      //desconectamos la base de datos
      $close = mysqli_close($conexion)
      or die("Ha sucedido un error inexperado en la desconexion de la base de datos");

      //Creamos el JSON
      $json_string = json_encode($organismos, JSON_FORCE_OBJECT);
      echo $json_string;

      //Si queremos crear un archivo json, sería de esta forma:
      /*
      $file = 'organismos.json';
      file_put_contents($file, $json_string);
      */

      ?>

      Eliminar
    4. No se porque no me deja poner el codigo entero....

      Te pongo uno de los errores que me aparecen: org.json.JSONException: No value for Servicios

      https:/dl.dropbox.com/s/zeejgy8493z8vzs/db.php?dl=0

      Esto viene de la parte de codigo:
      // Getting JSON Array node
      pers = jsonObj.getJSONArray("Servicios");

      Eliminar
    5. Buenas!!! Hace mucho que no toco .php pero más o menos entiendo que pone =)
      Ok, no te dejará postear el código porque tendrán los de blogger un minimo de seguridad para la inyección por código javascript.
      Respecto a este enlace :
      http://www.bdmacotera.besaba.com/bdMacoteraConecta/db.php

      Es lo que te comentaba, adaptandolo a tus necesidades has cambiado la jerarquia de Objects y Arrays, te paso un JSON con la jerarquía correcta para que lo amoldes, o por el contrario, modifiques tu clase Java con el tuyo.
      https://www.dropbox.com/s/14tbosysfstsb3d/productos.json?dl=0

      Pienso que el problema está en que donde en mi json si te das cuenta pone Productos, englosa toda la categoría, mientras que en el tuyo pones numeros como 0,1,2.... englosa una categoria a un objeto, y algo se debe rallar en el bucle for siguiente. Vamos, en una explicación normal, el mio coge un array y después recoge objetos, en el tuyo por el contrario, tienes un array lleno de arrays... Dios, como cuesta explicarse a estas horas!

      Espero haberte sido de ayuda,

      Saludos!

      Eliminar
    6. Y por cierto, para ayudarte a resolver el problema, te recomiendo que uses https://www.jsoneditoronline.org/ que es un editor online de JSON, seguro que te ahorra más de un rato en la construcción del JSON!

      Eliminar
    7. Muchas gracias, probare y ya te contare...:D

      Eliminar
    8. Buenas de nuevo Makone, al utilizar como base tu código y modificar el JSON que me pasaste, lo he modificado para que me muestre mis datos, al ejecutar en el emulador me sale el siguiente mensaje:
      05-27 18:10:58.976 4913-4913/? E/dalvikvm﹕ could not disable core file generation for pid 4913: Operation not permitted

      Sin embargo con el tuyo sigo sin tener problemas...aunque tambien me aparece un mensaje similar.

      No veo diferencias entre código, el tuyo sigue mostrándome tus datos pero el mio se queda en blanco.

      Eliminar
  2. En primer lugar darte las gracias y la enhorabuena por el tutorial.
    Gracias a el he aprendido a usar Android y JSON juntos.
    Estoy desarrollando una aplicación y tengo el siguiente problema:
    Cuando obtengo las imágenes del archivo JSON colgadas en mi dropbox, se ve en la interfaz del teléfono o del emulador como las imágenes recorren todas la primera posición del array, y una vez que han pasado por todas imagens, entonces empiezan a colocarse cada una en el lugar que le corresponde. En vez de colocarlas directamente, como el resto de los datos (nombre, edad, etc.)
    Me gustaría que me ayudes a resolver mi problema.
    Muchas gracias de antemano, Salu2.

    ResponderEliminar
  3. Buenos días, muy buena página. Tengo una duda. Quiero hacer un proyecto que en lugar de llamar al archivo json desde un servidor remoto lo tenga incluido dentro de una de las carpetas del proyecto. Necesito saber como se hace.
    Saludos a todos

    ResponderEliminar
  4. Excelente información!, lo compilé en Android Studio y funcionó de inmediato.

    ResponderEliminar
  5. Hola, saludos
    en primer lugar quisiera felicitar y agradecer por el material entregado, es claro y fácil de entender.
    Solo tengo una duda, no puedo descargar el ejemplo, no se si me puedes ayudar con esto. gracias.

    ResponderEliminar
  6. Hola, saludos
    en primer lugar quisiera felicitar y agradecer por el material entregado, es claro y fácil de entender.
    Solo tengo una duda, no puedo descargar el ejemplo, no se si me puedes ayudar con esto. gracias.

    ResponderEliminar
  7. Buenos dias me podrias ayudar con el ejmeplo.

    ResponderEliminar
  8. Buen dia, mucas gracias por el codigo

    ResponderEliminar
  9. y los enlaces de descarga el proyecto?

    ResponderEliminar
  10. buen dia, por favor quisiera saber porque ocurre este error
    Unterminated string at character 50000 of {"ObjListaTalleres":[{"CODHOR������������������������������������������������������

    ResponderEliminar