martes, 5 de febrero de 2013

Librería HTTP para Android

Los desarrolladores Android saben lo complicado que es la configuración de la Librería Apache HTTP Components que nos provee la API de Android. Necesitamos setear timeouts, protocolos, y crear por nuestra cuenta Threads, lógica de reintentos, chequeo de conexión a Internet,etc.

En el Laboratorio de Software Libre hemos desarrollado una librería que maneja todas estas cuestiones internamente, proporcionando al programador una herramienta muy fácil de utilizar.

Descargar Http Manager for Android 2.0

La página de descarga nos ofrece bajar la librería (.jar que podemos incluir en el proyecto) o un proyecto de demo (HttpManagerDemo2.0), explicaremos a continuación el proyecto de Demo para mostrar lo fácil que es la utilización de esta librería para realizar requests HTTP hacia un Web Service.

En el proyecto tenemos dos packages

  • ar.com.gnutnfra.httpmanager : Esta es nuestra librería, puede incluirse el JAR en vez de estos archivos.
  • ar.com.gnutnfra.httpmanagerdemo : Aquí tenemos dos clases, una Activity, y una clase que define las URL que utlizará la librería.


Explicaremos la clase "MyProtocol". Es una clase que hereda de "Protocol". El constructor de nuestra clase le pasará a la clase padre la URL base de nuestro Web Service.
 public MyProtocol(String urlBase) {
  super(urlBase);
 }
Luego redefinimos el método "getUrlFromCmd"

 @Override
 public String getUrlFromCmd(int cmd) {
  { 
   switch(cmd)
   {
    case CMD_GET_IMG : return getUrlBase() +   "getImg.php"; 
    case CMD_GET_DATA_1 : return getUrlBase() +  "getDataDetalleReunion.php";
    case CMD_GET_DATA_2 : return getUrlBase() +  "getDataDetalleProyecto.php";
    case CMD_GET_DATA_POST : return getUrlBase() +  "postData.php";
    case CMD_GET_IMG_POST : return getUrlBase() +   "postImg.php";
   }  
   return "";
  }
 }
La idea es definir constantes numéricas que representen las direcciones web que vamos a utilizar, y poner un switch que devuelve la URL según la constante pasada como arguemento. Por ello es que en nuestra clase "MyProtocol" también definimos las constantes para cada URL:

 public static final int CMD_GET_IMG=0;
 public static final int CMD_GET_DATA_1=1;
 public static final int CMD_GET_DATA_2=2;
 public static final int CMD_GET_DATA_POST=3;
 public static final int CMD_GET_IMG_POST=4;
En nuestra Activity, utilizaremos estas constantes para ejecutar los Requests HTTP.

Pasemos ahora al código de la Activity, en donde deberemos implementar una interfaz llamada "HttpManagerListener" la cual nos informará cuando lleguen las respuestas HTTP, o en el caso de error, si no había conexión a Internet, o si se agotaron los reintentos hacia el WS.
public class MainActivity extends Activity implements HttpManagerListener{
Los métodos que esta interfaz nos obligará a implementar son:
  • retriesExceeded : Se ejecuta si los reintentos se agotan al ejecutar un Request.
  • internetConnectionFailed : Se ejecuta si no hay conexión a Internet al ejecutar un Request.
  • newMsg : Se ejecuta cuando llega la respuesta del Request.
Explicaremos ahora como ejecutar un Request.

Primero debemos crear un objeto "MyProtocol" en donde se definen como ya se explicó, las URLs que utilizaremos, y luego un objeto HttpManager, mediante el cual ejecutaremos los Request. Este objeto recibe como parámetros:

  • Un objeto HttpManagerListener (en este caso la propia Activity ya que implementa la interfaz)
  • El Context.
  • Un objeto Protocol (el que creamos anteriormente).
        Protocol protocol = new MyProtocol("http://www.ucpic.byethost7.com/wsPP/");
        httpm = new HttpManager(this,this,protocol);
Ahora podemos ejecutar un Request, existen dos funciones, una para obtener textos como respuestas (XML, JSON,etc) y otra para obtener bytes (Utilizada para obtener archivos de imagen)

Obtener JSON por GET


Primero deberemos crear una lista de pares "Clave-Valor", para ello utilizaremos las mismas listas de la librería de Apache:
        List nameValuePairs = new ArrayList();
        nameValuePairs.add(new BasicNameValuePair("idProy","1"));
En el ejemplo, pasamos la clave "idProy=1". Ahora ejecutamos el request, como se mencionó anteriormente, en vez de la URL utilizaremos las contantes definidas en "MyProtocol", en este caso "MyProtocol.CMD_GET_DATA_1" y ejecutamos el método "txtRequestWithRetries" del objeto HttpManager que habiamos creado.

httpm.txtRequestWithRetries(MyProtocol.CMD_GET_DATA_1,nameValuePairs,HttpManager.PROTOCOL_GET);
Como último parámetro, indicamos que el protocolo será GET, en el caso de ser POST, existe la constante "PROTOCOL_POST"

Recibiendo la respuesta.


Como dijimos con anterioridad, el método "newMsg" se ejecutará al llegar la respuesta, y en su argumento obtendremos un objeto "MsgData", este objeto posee el método "getCommand" el cual corresponderá con la constante con la que hicimos el Request, de modo que en este método colocamos un switch por cada constante que representa una URL en nuestra clase "MyProtocol".
  switch(msg.getCommand())
  {
   case MyProtocol.CMD_GET_DATA_1:
   case MyProtocol.CMD_GET_DATA_POST:
   {
    Log.d("demo","Internet Data:"+msg.getInternetData());
    break;
   }
El objeto "msg" posee el método "getInternetData()" el cual nos devolverá un String con la respuesta desde el Servicio Web. En el caso de que la respuesta sea una imagen, utilizaremos el método "getImgData" el cual nos devolverá un array de bytes.