domingo, 26 de octubre de 2014

Comunicación Http

La comunicación Http es necesaria para conectar con una aplicación web desde el dispositivo móvil. Como parte de la implementación Java de Android se incluyen las clases URL y HttpURLConnection con las cuales es posible emplear comunicación básica con el servidor.
En Android además se introducen clases provenientes del paquete org.apache.http que encapsulan peticiones y respuestas al servidor para una gestión sencilla de las conexiones.

Compatibilidad

v1

Lo mínimo necesario

Es necesario permiso de Internet en el Manifest:
<uses-permission android:name="android.permission.INTERNET"/>

Una clase que represente el objeto del servidor:
public class Equipo implements Serializable{
      
    private String nombre;
    private float presupuesto;
    private int clasificacion;
    private int gf;
    private int gc;
   
    public Equipo(){
       
    }

    public Equipo(String nombre, float presupuesto, int clasificacion,
int gf, int gc) {
        this.nombre = nombre;
        this.presupuesto = presupuesto;
        this.clasificacion = clasificacion;
        this.gf = gf;
        this.gc = gc;
    }

    public int getClasificacion() {
        return clasificacion;
    }

    public void setClasificacion(int clasificacion) {
        this.clasificacion = clasificacion;
    }

    public int getGc() {
        return gc;
    }

    public void setGc(int gc) {
        this.gc = gc;
    }

    public int getGf() {
        return gf;
    }

    public void setGf(int gf) {
        this.gf = gf;
    }

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public float getPresupuesto() {
        return presupuesto;
    }

    public void setPresupuesto(float presupuesto) {
        this.presupuesto = presupuesto;
    }

    public String toString(){
        return nombre;
    }
            
}

Una clase para conectar con el servicio a través de la conexión Http. Cuando los datos se reciben se procesan con la API Gson, que deberá estar configurada en el proyecto Android, y se encarga de reconstruir los objetos de forma automática:
public class EnviarHttp {
      
//Codificación empleada
public static final String ENCODING = "UTF-8";
      
private static final String PARAM_OP = "op";
private static final String OP_EQUIPOS = "equipos";
      
private Context context;
      
       public EnviarHttp(Context context){
             this.context = context;
       }

       /**
        * Envío de solicitud HTTP
        * @return
        * @throws Exception
        */
       public List<Equipo> callService() throws Exception {
             List<Equipo> res = null;
            
             InputStream is = null;
            
             HttpClient client = new DefaultHttpClient();      
            
             try {
                    //La solicitud será a la URL que determine el parámetro
                    HttpPost post =
new HttpPost(context.getString(R.string.ws_url));
                   
                    //Enviar los parámetros          
List<NameValuePair> params =
new ArrayList<NameValuePair>();
                    params.add(
                          new BasicNameValuePair(PARAM_OP, OP_EQUIPOS));
                    post.setEntity(new UrlEncodedFormEntity(params));
              
                    //Lanzar petición
              HttpResponse response = client.execute(post);
              
                    // Procesar la información
                    is = response.getEntity().getContent();
                    res = this.procesar(is);
             } finally {
                    // cerrar las conexiones
                    if (is != null) {
                           is.close();
                    }
             }
            
             return res;
       }
      
       /**
        * Método para obtener la respuesta
        * @param is stream de entrada con los datos a procesar
        * @return objeto procesado
        * @throws IOException error en la conexión
        */
       public List<Equipo> procesar(InputStream is) throws IOException{
             List<Equipo> res = new ArrayList<Equipo>();
            
             //Configurar objeto para recibir la información
             Gson gson = new GsonBuilder().
setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            
             BufferedReader br =
new BufferedReader(new InputStreamReader(is, ENCODING));
             String linea;
             if ((linea = br.readLine()) != null){
                    //La respuesta viene en una sola línea
                    Type listType =
new TypeToken<List<Equipo>>(){}.getType();
                    //Devolver
                    res = gson.fromJson(linea, listType);
             }
            
             return res;
       }
}

Es necesario que la URL de conexión sea de un servidor no local (la dirección localhost o 127.0.0.1 no son permitidas). En caso de estar desarrollando en una misma máquina se deberá usar la IP local de la misma.
Invocar a la clase anterior desde una tarea asíncrona:
private class TareaEnvio extends AsyncTask<String, Integer, List<Equipo>> {

       private ProgressDialog dialog;
                   
       @Override
       protected void onPreExecute() {
              dialog = ProgressDialog.show(MainActivity.this,
                                  getString(R.string.app_name),
getString(R.string.buscando), true);
       }

       @Override
       protected List<Equipo> doInBackground(String... args) {
              List<Equipo> res = null;
              try {
                    EnviarHttp client = new EnviarHttp(MainActivity.this);
                    res = client.callService();
              } catch (Exception ex) {
                    ex.printStackTrace();
                    res = null;
              }
              return res;
       }

       @Override
       protected void onPostExecute(List<Equipo> result) {
              dialog.dismiss();
                          
//Utilizar el resultado en el interfaz gráfico
Spinner sp = (Spinner) findViewById(R.id.spEquipo);
sp.setAdapter(new ArrayAdapter<Equipo>(MainActivity.this,
android.R.layout.simple_list_item_1,
(ArrayList<Equipo>)result));
       }
}

Parámetros de conexión

En ocasiones es necesario especificar algunos parámetros en la conexión Http. Para ello se empleará una instancia de HttpParams. En el siguiente ejemplo se emplean parámetros para indicar un timeout, de forma que si la conexión no se establece en un periodo determinado se corta para no dejar a la app esperando de forma indefinida.
private static final int TIME_CONN = 5000;
private static final int TIME_SOCK = 15000;

public List<Equipo> callService() throws Exception {
       List<Equipo> res = null;
            
       InputStream is = null;
            
       HttpParams httpParameters = new BasicHttpParams();
       //Timeout para conectar, por defecto 0 (0 indica que no hay timeout)
       HttpConnectionParams.setConnectionTimeout(httpParameters,TIME_CONN);
       //Timeout para obtener datos
       HttpConnectionParams.setSoTimeout(httpParameters, TIME_SOCK);
       HttpClient client = new DefaultHttpClient(httpParameters);
...

Referencias

http://developer.android.com/reference/org/apache/http/params/HttpConnectionParams.html

No hay comentarios:

Publicar un comentario