Operaciones HTTP En Android Con El Cliente HttpURLConnection

Este artículo explicará de qué forma se puede enviar y recibir datos hacia un servidor desde una aplicación Android, con el propósito de introducir a los desarrolladores a la creación de servicios en la nube desde fuentes de datos externas.

En primera instancia se expondrán conocimientos introductorios sobre el protocolo HTTP, el cual habilita el intercambio de información.

Luego verás a través de un ejemplo práctico como leer y postear comentarios en un servidor externo. Y Adicionalmente se integrarán las tareas asíncronas para asegurar el correcto funcionamiento del hilo principal.

Finalmente se concluye con aspectos adicionales del mecanismo usado para la conexión y observaciones que pueden ayudarte en la conexión de las aplicaciones Android.

Introducción al funcionamiento del protocolo HTTP

Las conexiones que haremos desde nuestras aplicaciones Android hacia los servidores web siguen un estándar internacional llamado Hipertext Transfer Protocol HTTP. Este protocolo consiste en reglas sencillas de transferencia de recursos o archivos entre equipos interconectados a una red.

Al equipo que hace la petición para enviar u obtener datos se le llama Cliente y al que contiene el recurso o el espacio para almacenar es llamado Servidor.

La comunicación se establece a través de una petición de envío, la cual contiene los datos del cliente, como el sistema operativo que usa, el navegador web desde donde se hace la petición, la ubicación del archivo solicitado (URL), etc.

Diagrama de una petición y respuesta en el protocolo HTTP
Una petición puede tener múltiples objetivos dependiendo del método que se elija. Los tipos de peticiones más comunes son el Retorno de datos y la Publicación de datos. Técnicamente se les conoce como los métodos GET y POST.

La búsqueda de una página web a través de la URL es un buen ejemplo de una petición GET, donde el cliente especifica la URL y el servidor retorna en la información HTML necesaria para que el navegador realice su respectivo parsing.

El ejemplo más popular del método POST se refleja en el envío de información desde un formulario hacia la base de datos del servidor. Aquí hacemos lo contrario, dictaminamos los datos y el servidor los recibe para almacenarlos y darles persistencia.

Cada vez que entras a hermosa programación desde tu navegador la comunicación HTTP sería similar a esta:

GET /index.html
Host: www.hermosaprogramación.com
User Agent: Mozilla/4.0 (Compatible; MSIE 7.0; Windows NT 6.0)
Accept: */*

Dicha petición es recibida por el Servidor, quién arroja la respuesta dependiendo del estado del recurso solicitado, que en este caso es el archivo HTML que representa el Home de Hermosa Programación.

HTTP/1.0 200 OK
Date: Fri, 27 Dec 2014 23:59:59 GMT
Content-Type: text/html
Content-Length: 1467

<html>
<body>
<h1>Hermosa Programación</h1>
(El contenido restante)
  .
  .
  .
</body>
</html>

Como se nota, el estado de respuesta es 200 OK, un código que significa que todo marcha sobre ruedas con este recurso. En seguida se ubican metadatos asociados a la fecha de consulta, el tipo de contenido enviado, su tamaño y al final el contenido HTML. Con esta información, tu navegador web ya puede implementar la lógica necesaria para mostrar la página web.

Ahora veamos el esquema de una petición POST, cuyo objetivo es enviar los datos Nombre y Precio hacia la base de datos del servidor:

POST /data/Insertar-Productos.php HTTP/1.0
From: frog@jmarshall.com
User-Agent: HTTPTool/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 25

Nombre=Motorola&Precio=2000

En este caso se indica la ruta de ubicación donde se publicaran los resultados, una cuenta de correo como el origen de la petición, el tipo de contenido estándar para los formularios, el tamaño de los datos y finalmente dos pares clave-valor encriptados con UTF-8.

Si deseas que tus aplicaciones tengan acceso total a la conexión de tu dispositivo Android es necesario que incluyas los siguientes permisos en tu archivo AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Ejemplo: Aplicación Monstalkers Para Lectura Y Posteo De Comentarios

Monstalkers es una aplicación de ejemplo creada para mostrar el uso del cliente HttpURLConnection.

Su objetivo es mostrar como cargar comentarios almacenados en un servidor externos a través del parsing de un arreglo JSON.

Adicionalmente permitirá al usuario crear y enviar su propio comentario al servidor.

Puedes descargar el código siguiendo estas instrucciones:

En cuanto a diseño, Monstalkers se compone de dos actividades.

La primera es la actividad principal llamada MainActivity, donde se muestra un ListView que despliega todos los comentarios por orden cronológico.

Su Action Bar tiene dos botones de acción, los cuales permiten añadir un nuevo comentario y refrescar la vista respectivamente.
Aplicación Android para Añadir Comentarios a un Servidor
Cuando se presiona el action button para añadir, inmediatamente se despliega la actividad FormActivity, la cual contiene un sencillo campo de edición para digitar el comentario. El usuario decidirá el fin del comentario presionando el botón Enviar o Cancelar.
Actividad Android con un Formulario para añadir Comentarios

Usar el cliente HttpURLConnection

La clase HttpUrlConnection del paquete java.net.* permite a nuestros dispositivos android asumir las características de un cliente HTTP ligero. Su funcionamiento está condicionado a las versiones superiores a Gingerbread. Para versiones anteriores debes usar el cliente HttpClient de Apache.

Con esta clase podremos recibir y enviar información a través de la web, lo que potenciará nuestras aplicaciones Android. A continuación se muestran los pasos que se deben realizar para establecer una conexión exitosa.

Comprobar si la conexión a la red es posible

Antes de iniciar el cliente Http debes comprobar si la conexión del dispositivo está habilitada, ya que puede ser posible que el Wi-fi no esté disponible o simplemente la conexión de red está fuera del rango. Para comprobar el estado de conexión usaremos los métodos getActiveNetworkInfo() e isConnected():

ConnectivityManager connMgr = (ConnectivityManager) 
    getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
if (networkInfo != null && networkInfo.isConnected()) {
    // Operaciones http
} else {
    // Mostrar errores
}

Se ha usado la clase ConnectivityManager para obtener las características actuales de la conexión. Esta información la guardamos en un elemento del tipo NetworkInfo con el método getActiveNetworkInfo(). Luego comprobamos si se retornó algún dato y si además el dispositivo está conectado con isConnected().

Abrir la conexión hacia el servidor

El primer paso para iniciar la comunicación es abrir la conexión hacia el recurso alojado en el servidor. Para ello se usa el método openConnection() de la clase URL. El resultado que se obtenga debe ser casteado a HttpUrlConnection para que el cliente sea instanciado:

URL url = new URL("http://monstalkers.hostoi.com/data/get_all_comments.php");   
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

Obtener datos con el método GET

Si deseas descargar datos desde la URL especificada simplemente usas el método getIntpuStream() para obtener el flujo de datos asociado al recurso que se encuentra en esa dirección:

URL url = new URL("http://monstalkers.hostoi.com/data/get_all_comments.php");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
 InputStream in = new BufferedInputStream(urlConnection.getInputStream());
 // Acciones a realizar con el flujo de datos
finally {
 urlConnection.disconnect();
}

Es importante que al finalizar tus operaciones de conexión liberes la memoria asociada a la instancia de la conexión realizada. Para ello usa el método disconnect(), el cual pone a disposición de nuevo una futura reconexión.

Recuerda que un tipo InputStream debe ser decodificado para interpretar su contenido, ya sea texto plano, imagen, JSON, audio, etc. Dependiendo del objetivo así mismo debes usar los métodos y técnicas correspondientes.

Postear información con el método POST

Si deseas publicar información en un servidor debes abrir la conexión al igual que con GET. Luego se indica a la conexión que se permite el envío de datos hacia el servidor con el método setDoOutput().

Seguidamente se declaran los datos que se enviarán al destino, para los cuales debes declarar el tamaño que ocuparán para ser transmitidos por el flujo.

Si su tamaño es fijo, entonces usa el método setFixedLengthStreamingMode(), quién recibe como parámetro la cantidad de bytes.

Si el tamaño es incierto (normalmente esta situación se da en transmisiones Streaming), entonces usa setChunkedStreamingMode().

Reuniendo todas estas características, Monstalkers hace su publicación de comentarios de la siguiente forma:

// Obtener la conexión
HttpURLConnection con = null;

try {
    // Construir los datos a enviar
    String data = "body=" + URLEncoder.encode(comment,"UTF-8");

    con = (HttpURLConnection)url.openConnection();

    // Activar método POST
    con.setDoOutput(true);

    // Tamaño previamente conocido
    con.setFixedLengthStreamingMode(data.getBytes().length);

 // Establecer application/x-www-form-urlencoded debido a la simplicidad de los datos
    con.setRequestProperty("Content-Type","application/x-www-form-urlencoded");

    OutputStream out = new BufferedOutputStream(con.getOutputStream());

    out.write(data.getBytes());
    out.flush();
    out.close();

} catch (IOException e) {
    e.printStackTrace();
} finally {
    if(con!=null)
    con.disconnect();
}

El código anterior muestra como se envía el cuerpo de un comentario digitado por el usuario en la actividad ActivityForm. En primera instancia se construye una cadena llamada data, donde guardaremos el par clave-valor del comentario con el estándar de formularios “clave= valor”. Para ello usamos la clave “body” como representación del cuerpo del comentario como tal, cuyo valor se encuentra almacenado en la variable comment.

Luego se encriptó el parámetro con el método estático encode de la clase URLEncoder. Esta clase permite ajustar la cadena al sistema UTF-8 para que sea compatible con el tipo de contenido application/x-www-form-urlencoded, de acuerdo a los estándares de envío de información para el método POST establecido por la W3C.

Aunque en este ejemplo se usa un solo par clave-valor, a menudo necesitarás enviar múltiples pares. Para ello solo debes concatenarlos con el carácter ‘&’ de acuerdo al estándar.

El siguiente paso fue declarar el envío de datos con setDoOutput(), seguido se estableció el valor en bytes de nuestros datos y además se añadió el tipo de contenido con setRequestProperty(). Este método te permite añadir cabeceras a la petición que envíes.

Finalmente se obtiene acceso al sistema de archivos del servidor con getOutputStream(), el cual retorna en un flujo de datos en donde escribirás los datos de los comentarios a través de los métodos flush() y write().

Subir un archivo hacia un servidor con el método POST

En la sección anterior se usó el tipo de contenido application/x-www-form-urlencoded para enviar datos atómicos hacia el servidor, pero… ¿Qué hacer para subir un archivo?

Una de las formas es usar el tipo de contenido multipart/form-data del estándar W3C para enviar datos binarios de gran tamaño. Pero la verdad me resulta complicado preparar todas las sentencias de texto requeridas para dirigir el flujo de información.

En su lugar puedes publicar el archivo directamente como bytes puros a través de getOutputStream() de la siguiente forma:

File file = new File("ruta_del_archivo");
URL url = new URL("http://www.tuservidor.com/");
HttpURLConnection con = null;

try{
    con = (HttpURLConnection)url.openConnection();

    // Activar método POST
    con.setDoOutput(true);

    // Tamaño desconocido
    con.setFixedLengthStreamingMode(0);

    OutputStream out = con.getOutputStream();
    // Usas tu método ingeniado para convertir el archivo a bytes
    out.write(convertfileToBytes(file));
    out.flush();
    out.close();
}finally{
    if(con!=null)
    con.disconnect();
}

Establecer peticiones HTTP en segundo plano usando AsyncTask

El tiempo que tarda la transmisión de datos en la red depende de muchos factores, como el tamaño de la información a intercambiar, los tiempos de latencia, la congestión del servidor o incluso la ejecución de múltiples tareas distintas en el sistema operativo. Cualquiera de estas situaciones puede prolongar el tiempo de una petición indefinidamente.

Pero como tú ya sabes, las tareas asíncronas nos auxilian en estas situaciones. Solo debemos crear una nueva instancia de la clase AsyncTask e incluir la petición al servidor en el método doInBackground() y luego actualizar los resultados visuales en onPostExecute().

Lee también Uso de Hilos y tareas asíncronas (AsyncTask) en Android

Por ejemplo, la obtención de todos los comentarios que se han guardado en el servidor de monstalker ha sido encapsulada en una clase llamada GetCommentsTask:

public class GetCommentsTask extends AsyncTask<URL, Void, List<String>> {

    @Override
    protected List doInBackground(URL... urls) {

        List comments = null;

        try {

            // Establecer la conexión
            con = (HttpURLConnection)urls[0].openConnection();

            // Obtener el estado del recurso
            int statusCode = con.getResponseCode();

            if(statusCode!=200) {
                comments = new ArrayList();
                comments.add("El recurso no está disponible");
                return comments;
            }
            else{

                /*
                Parsear el flujo con formato JSON a una lista de Strings
                que permitan crean un adaptador
                 */
                InputStream in = new BufferedInputStream(con.getInputStream());

                JSONCommentsParser parser = new JSONCommentsParser();

                comments = parser.readJsonStream(in);

            }

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

        }finally {
            con.disconnect();
        }
        return comments;

    }

    @Override
    protected void onPostExecute(List s) {

        /* Se crea un adaptador con el el resultado del parsing
        que se realizó al arreglo JSON
         */
        ArrayAdapter adapter = new ArrayAdapter(
                getBaseContext(),
                android.R.layout.simple_list_item_1,
                s);

        // Relacionar adaptador a la lista
        comments.setAdapter(adapter);
    }
}

La secuencia de la tarea tendría la siguiente estructura:

  • Abrir la conexión hacia la URL en doInBackground().
  • Obtener el estado del recurso con getResponseCode(). Si la respuesta no es 200 OK, entonces preparar un valor de retorno que indique el error sucedido.
  • En caso de éxito, entonces se obtiene el flujo de datos con getInputStream()
  • Parsear o formatear dependiendo del flujo. En este caso particular la información viene como un arreglo de objetos JSON. Para traducirlo en información legible se ha implementado la clase JSONCommentsParser, la cual usa la clase android.util.JsonReader para leer los bytes y recorrer la estructura, de tal forma que al final se retornen los datos que interesan (una lista de comentarios).
  • Finalmente se realizan las acciones necesarias en onPostExecute(). MonsTalkers implementa crea un adaptador nuevo basado en el parámetro recibido y luego lo asocia al ListView.

Si deseas formatear un flujo a Bitmap puedes usar el método estático decodeStream() de la clase BitmapFactory, el cual recibe como parámetro un tipo InputStream. Si en lugar de un bitmap, tienes texto plano, entonces puedes usar un objeto InputStreamReader, el cual puede convertir bytes a caracteres (char) y finalmente convertir a String.

Otros métodos para peticiones HTTP en Android

El método por defecto asociado a un objeto HttpURLConnection es GET. Cuando abres la conexión es sencillo obtener el flujo asociado a la URL con tan solo usar getInputStream().

El método POST tampoco es complicado de emplear, ya que solo se activa con setDoOutput() para estructurar los datos a enviar y escribir sobre el flujo de salida.

Pero en el caso de otros métodos como OPTIONS, HEAD, PUT, DELETE o TRACE debes usar el método setRequestMethod() para hacer efectiva la petición. No obstante este también se puede usar para especificar los métodos GET y POST.

con.setRequestMethod("GET");

Otra característica adicional de la clase HttpURLConnection es la capacidad de establecer los tiempos de caducidad de conexión y tiempos de caducidad de lectura a través de los métodos setConnectTimeout() y setReadTimeout():

// Expirar a los 10 segundos si la conexión no se establece
con.setConnecTimeout(10000)
// Esperar solo 15 segundos para que finalice la lectura
con.setReadTimeout(15000)

Conclusiones y Recomendaciones

El cliente HttpURLConnection nos permite usar métodos de petición de forma eficaz y amigable. Solo se indica la ubicación del recurso a través de una URL, luego defines tu propósito. Si el objetivo es obtener información, entonces asegúrate de crear un método que parsee la información con el formato correcto.

Por el contrario si se enviarán datos, entonces procura constituir pares clave-valor siguiendo el estándar. Adicionalmente recuerda usar tareas asíncronas ejecutar tus peticiones, de lo contrario el framework de Android te arrojará una excepción perteneciente al modo restringido, donde se te explica que no es permitido ejecutar peticiones en el hilo principal.

Aunque este cliente es una alternativa congruente, Google recomienda usar la librería HTTP Volley. Esta herramienta permite transmitir datos a través de la red en un alto nivel, debido a que establece una capa superior para evitar manejar el flujo de datos directamente, relaciona la fase de parsing con facilidad y optimiza el rendimiento de las operaciones. Pero este será un tema para otro artículo.

  • Mario Cardona

    es compatible con la API 23 ?

  • Gustavo Londoño

    Buenas, tengo un proyecto donde debo enviar un numero obtenido desde un lector de codigoqr a mysql si alguien conoce como realizarlo agradeceria la colaboración.

  • Gustavo Londoño

    Buenas, tengo un proyecto donde debo enviar un numero obtenido desde un lector de codigoqr a mysql si alguien conoce como realizarlo agradeceria la colaboración.

    • Carlos Perez

      Hola yo realicé un proyecto similar a lo que comentas

  • Edgar Enrique Cabello Peña

    Buenas,
    Estoy realizando una aplicacion que necesito pasar la cookie obtenida de una conexion HTTPURLCONNECTION a otra actividad y no se como puedo hacer eso para que asi no se pierda la conexion con mi webservice cuando cambio de actividad, no se si me pueden colaborar por favor.

  • Rafael Muñoz Gonzalez

    Buenas noches!!
    Estoy realizando el apartado de “Postear información con el método POST” y resulta que cuando llego a la siguiente linea da error :(OutputStream out = new BufferedOutputStream(con.getOutputStream());
    Me podíais informar a que es devido?

    Un saludo y gracias de antemano!

  • Gabriel Atahualpa Sanchez

    Hola! Podrias añadir algo sobre le manejo de las excepciones especificas cuando se utilizan estos metodos? Por ejemplo, que se podria hacer con “malformedurlexception”, y al usar el e.printStackTrace(); me parece que queda muy basico y esto seria un hadicap my importante en la app no?

  • José

    Saludos, tengo un problema con el codigo de la sección “Subir un archivo hacia un servidor con el método POST”, cuando escribo la sentencia out.write(convertfileToBytes(file)); convertfileToBytes no la reconoce. Alguna idea?

  • Keyshax

    Saludos, tengo una pequeña duda, adapte el ejemplo a una tabla persona id, nombre, apellidos. Pero no me realiza las acciones de guardar, editar, eliminar. Solo son exitosas cuando debuggueo la aplicación. Alguna razón de porque sucede esto?

  • Ana Rotela

    Buenas noches, excelente los tutoriales de hermosa programacion. Una consulta de donde podria descargar el codigo de “http://monstalkers.hostoi.com/data/get_all_comments.php”)?
    por favor. Saludos y Gracias desde Paraguay.

  • Alvaro

    Buenas tardes,

    Una información muy utíl y muy bien redactada.
    Con
    su permiso reutilizare partes del código para una app que estoy
    desarrollando en la cual requiero escribir en un servidor diferentes
    estados por los cuales pasa la aplicación.

    Comparti este post tan interesante en twitter ya que seguro que a muchas más personas podría venirle bien.(@AlvaroIVM)

    Muchas gracias por un contenido de tanto valor!

    Un Saludo!

    Att. Álvaro I. Valderrama Molina

  • Farameo

    hola el link para bajar no funciona mas. podes arreglarlo? gracias.

  • sanreikaj

    Compartí el tweet para conseguir el código pero no veo donde bajarlo, como puedo hacer para conseguirlo?

  • PiRu

    Buenos días,
    estoy intentando enviar una imagen a un servicio web. Tal que así:

    con = (HttpURLConnection) url.openConnection();
    // Activar método POST
    con.setDoOutput(true);

    // Tamaño desconocido
    con.setFixedLengthStreamingMode(0);

    out = con.getOutputStream();

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
    byte[] dataByte = stream.toByteArray();
    out.write(dataByte);
    out.flush();
    out.close();
    con.disconnect();
    Pero ¿Como la recibo en mi PHP? No se como referirme a la información en bytes. Tal como para enviar datos le das un nombre y simplemente haces un $_POST[‘NOMBRE’] para recoger el dato, con los bytes no se como hacerlo. ¿Alguna orientación?

  • Carlos

    Buenas, una pregunta, soy novato en esto pero he podido enviar el comentario a mi base de datos gracias a tu código pero mi pregunta era como seria el código para poder enviar diferentes pares de de datos por el String, tu has puesto que se usa & , pero no me sale.

    // Construir los datos a enviar
    String data = “body=” + URLEncoder.encode(comment,”UTF-8″);

    Aquí querría enviar, nombre,apellidos,edad…

    Gracias un saludo, espero tu respuesta.

    • juan

      Debes de poner:

      String data = “nombre=” + URLEncoder.encode(nombre,”UTF-8″) + “&apellidos=” +URLEncoder.encode(apellidos,”UTF-8″) ;

  • Gon Her

    Hola James. Por este ando ya jaja. Bueno, resulta que por mala suerte para mi, en este tutorial, no compartiste nada del servidor y estoy como turco en la neblina jaja. perdido. Hace mucho vi este tutorial y lo dejé para ver despué sabiendo que tarde o temprano lo necesitaria. Porfavor, puedes compartir el web y el modelo de la DB? por favor. Saludos!
    PD. porfavor, pasalo.

    • Hola Gon. Si he estado pendiente por subir el contenido, solo que no he tenido tiempo. Espero hacerlo pronto.

  • Gerald Olivas

    hola. cual es el codigo de get_all_coments?

    • Hola compañero, voy a postearlo dentro de poco. Cuando escribí este articulo olvidé hacerlo.

  • Jorge

    Hola, el código de el archivo insert_comments.php donde lo podría conseguir? Muchas gracias por el tutorial!
    Un saludo.

  • Robert LUgo

    Hola James, de antemano buen trabajo bien redactado y conciso.
    Podrias por favor mostrar la estructura del archivo
    get_all_comments.php, gracias.

    • Hola Robert, lamentablemente acabo de acceder al hosting de prueba que usé y la cuenta se inhabilitó :v . Dejame subo el archivo a mi servidor actual y actualizo el articulo.

  • Leo HR

    Hola James, saludos.
    Tal vez me salga del contenido del curso. De antemano me disculpo.
    Disculpa, hay un software PC llamado Hercules Setup Utility, que dentro de las variadas funciones que tiene, hay una pestaña de nombre TCP Server, en el cual se establece un puerto que escucha alguna petición de alguna aplicación cliente.

    Dado lo anterior estoy haciendo una app en android donde ingresio la dirección IP de la PC donde se encuentra el software mencionado, y el puerto que establecí en el mismo.

    Pero no se cual es el código para llevar a cabo dicha conexión. Espero haberme explicado.
    Si tubieses alguna respuesta para mi me serviría de mucho, de antemano de doy las gracias por apoyar a toda la comunidad con este sitio.
    Saludos

  • icaiza

    Un tuto como mantener session. En varias peticiones y uso de cookie.

  • Iván Rivas

    Hola, ya puedo realizar una autenticación con el método get usando HttpURLconection, pero al momento de realizar la petición con post no funciona, ¿qué realizo mal?

    protected List doInBackground(URL… urls) {
    List aseguradoraList = null;
    String credentials = “apidroid” + “:” + “2hxvdJr8LbsrpwY”;
    String credBase64 = Base64.encodeToString(credentials.getBytes(), Base64.DEFAULT);

    try {
    // Establecer la conexión
    con = (HttpURLConnection)urls[0].openConnection();
    con.setDoOutput(true);
    con.setRequestMethod(“POST”);
    con.setRequestProperty(“Authorization”, “Basic “+credBase64);
    con.setConnectTimeout(15000);
    con.setReadTimeout(10000);

    // Obtener el estado del recurso
    int statusCode = con.getResponseCode();

    • Hola compañero, a que te refieres con que no funciona?, ¿que codigo de respuesta te sale?, ¿la app arroja error en el logcat?

  • Gloria Vlc

    Muchas gracias por el post, muy instructivo.
    Me gustaría hacerte una consulta. Estoy inmersa en un proyecto Android que, entre otras cosas, lee de una URL el contenido de un JSON y lo extrae, para mostrarlo por pantalla en un panel lateral deslizante.
    He implementado la funcionalidad de lectura, parseo y muestra por pantalla y me funciona perfectamente en eclipse. Pero cuando lo integro en el proyecto en Android Studio y lo hago correr en la Tablet, me da error en la línea de request.connect().
    El trozo de código es el siguiente:

    // Conexion con la URL
    URL url2 = new URL(url);
    HttpURLConnection request = (HttpURLConnection) url2.openConnection();
    request.connect();
    // Convierte a JSON object
    JsonParser jp = new JsonParser();
    // Convierte el input stream a json element
    JsonElement root = jp.parse(new InputStreamReader(request.getInputStream(), “utf-8”));
    // Recuperar contenido como JsonArray
    JsonArray array = root.getAsJsonArray();
    // Conversion a objeto iterable
    java.util.Iterator iter = array.iterator();
    // Captura del primer y unico elemento del array JSON
    JsonElement lista = iter.next();
    // Conversion de la lista a String
    String str = lista.toString();

    // Recupera claves y valores del JSON y los asigna al objeto Datos
    Gson gson = new Gson();
    datos = gson.fromJson(str, Datos.class);

    request.disconnect();

    return datos;

    Y el error que me sale es este:

    08-18 12:06:20.470 19640-19640/com.sygic.example.integdemo2d E/AndroidRuntime﹕ FATAL EXCEPTION: main

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sygic.example.integdemo2d/com.sygic.example.integdemo2d.SdkActivity}: android.os.NetworkOnMainThreadException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1968)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1993)
    at android.app.ActivityThread.access$600(ActivityThread.java:127)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1159)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4507)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:978)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:745)
    at dalvik.system.NativeStart.main(Native Method)

    Caused by: android.os.NetworkOnMainThreadException

    at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1099)
    at java.net.InetAddress.lookupHostByName(InetAddress.java:391)
    at java.net.InetAddress.getAllByNameImpl(InetAddress.java:242)
    at java.net.InetAddress.getAllByName(InetAddress.java:220)
    at libcore.net.http.HttpConnection.(HttpConnection.java:71)
    at libcore.net.http.HttpConnection.(HttpConnection.java:50)
    at libcore.net.http.HttpConnection$Address.connect(HttpConnection.java:351)
    at libcore.net.http.HttpConnectionPool.get(HttpConnectionPool.java:86)
    at libcore.net.http.HttpConnection.connect(HttpConnection.java:128)
    at libcore.net.http.HttpEngine.openSocketConnection(HttpEngine.java:308)
    at libcore.net.http.HttpEngine.connect(HttpEngine.java:303)
    at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:282)
    at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:232)
    at libcore.net.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:80)
    at com.sygic.example.integdemo2d.Datos.recuperarDatos(Datos.java:150)
    at com.sygic.example.integdemo2d.Datos.(Datos.java:51)
    at com.sygic.example.integdemo2d.Servicio.(Servicio.java:20)
    at com.sygic.example.integdemo2d.SdkActivity.onCreate(SdkActivity.java:108)
    at android.app.Activity.performCreate(Activity.java:4469)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1052)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1932)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1993)
    at android.app.ActivityThread.access$600(ActivityThread.java:127)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1159)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4507)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:511)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:978)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:745)
    at dalvik.system.NativeStart.main(Native Method)

    No tengo ni idea de por qué pasa esto. He puesto los permisos de Internet y Network_State en el AndroidManifest, así que por permisos no es. He de decir que es mi primer proyecto en Android
    Por favor podrías ayudarme a subsanar el error del connect()?

    Un saludo y gracias por anticipado.

    • Hola Gloria.

      ¿El código donde realizas la conexión se ejecuta dentro de una tarea asíncrona?

      Es lo único que se me ocurre que pueda estar molestando. Recuerda que las operaciones http no tienen una lapso de tiempo determinado, por lo que deben ser separadas en hilos de trabajo separados.

      • Gloria Vlc

        Uuuf no tengo ni idea de como hacer eso.
        He estado leyendo por los foros y creo que lo que pasa es que el tablet no soporta la librería HttpURLConnection, así que voy a probar con HttpClient.

        Gracias.

        • Gloria si te fijas en este tutorial yo uso una tarea asincrona llamada GetCommentsTask para poner en otro hilo la petición,por eso no se producen errores en la aplicación.

          Si aún no sabes como usar las tareas asincronas, te dejo el siguiente tuto:

          http://www.hermosaprogramacion.com/2014/12/android-asynctask-hilos/

          • Gloria Vlc

            Ok me voy a leer el tutorial de AsynTask y a ver si así me funciona, porque con HttpClient tampoco tira, me salta el error nada más empezar, al hacer
            HttpClient httpclient = new DefaultHttpClient() y el error es este:

            java.lang.RuntimeException: Stub!
            at org.apache.http.impl.client.AbstractHttpClient. (AbstractHttpClient.java:6)
            at org.apache.http.impl.client.DefaultHttpClient.(DefaultHttpClient.java:8)

            Así que seguramente es por eso de los hilos. Voy a intentar solucionarlo.
            Gracias James, ya te cuento como termina la película jeje.

          • Eso lo resolvés en un momentico Gloria.

            Saludos!

          • Gloria Vlc

            Lo conseguíiiii bieeeenn!!!, usando AsyncTask, tenías razón estaba bloqueando al hilo principal.
            Muuuchas gracias!!!

          • Jajja que bien Gloria, me alegro

  • Muchas Gracias !! excelente post , ya deje mi comentario jeje :D

  • Gaston

    Hola James ,, puede que el insert_comments.php no este funcionando ?? ya que posteo envio los datos me dice comentario agregado pero no lo agrega a la lista ,, Saludos y gracias por la info

  • Luis

    No esta muy Claro, y seria estupendo que se pueda colocar el nombre de quien posteo el comentario aunque sea de forma local. Saludos!

    • James Revelo

      Gracias por comentario Luis. Tendré en cuenta tus recomendaciones para una próxima actualización del artículo.

      Saludos!

  • jorge

    Buen tutorial pero se separó mucho de la información entre enviar un simple par clave-valor a un archivo. No queda completamente claro como realizar el enviar un archivo.

    • James Revelo

      Gracias por comentar Jorge :D

      Tendré en cuenta tus recomendaciones.

      Saludos