Conexión con APIs de Google

La aplicación que realizaremos nos permitirá realizar la traducción de un texto pequeño de español a inglés y además realizar una búsqueda en YouTube.

Queremos que al finalizar se vea así:

Disposición inicial

El tipo de requisiciones que realizaremos a estos APIs no necesita de autenticación entonces no necesitamos validar ningún tipo de credenciales. Si quisiéramos, por ejemplo, subir un video a YouTube sí sería necesario autenticarnos.

Para no realizar el trabajo desde cero nos apoyaremos en 2 librerías, una para cada API:

Vamos a usar esta librería en este demo sin preocuparnos mucho del tamaño final de la aplicación, al usarla en un ambiente de producción es muy importante utilizar ProGuard para reducir el tamaño, encuentran instrucciones detalladas en http://code.google.com/p/google-api-java-client/wiki/Setup

Vamos a importar varias librerías al proyecto, no utilizaremos código base de nuevo para seguir paso a paso la configuración:

  • Para la parte de traducción, es un único archivo llamado: google-api-translate-java-0.95
  • Para la parte de YouTube, del archivo zip que descargamos vamos a elegir 4 archivos, esta descarga trae varias librerías y sus fuentes, la descripción la encuentran en http://code.google.com/p/google-api-java-client/wiki/Setup nosotros vamos a utilizar del directorio raíz.
  • google-api-client-1.4.1-beta
  • google-api-client-googleapis-1.4.1-beta

Además, para la conexión HTTP y el parsing de JSON otras 2 de las dependencias: del archivo descargado de google-api-java-client dentro de la carpeta dependencies necesitamos:

  • guava-r09
  • jackson-core-asl-1.6.7

Para incluir nuestras librerías necesitamos hacer click derecho sobre el proyecto, luego propiedades:

Buscamos la pestaña de “Java Build Path” y de los botones del lado derecho hacemos click en “Add External JARs”:

Seleccionamos todas los archivos JAR de las librerías ya descritas y estamos listos:

Por último, vamos a configurar algunas cosas en el Manifest necesitamos permisos para Internet:

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

Diseño

El diseño tendrá 2 partes, para la traducción utilizaremos un TextView que le indique al usuario que hacer

<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Ingrese el texto a traducir"
	/>

Luego un LinearLayout para mostrar en fila un EditText para recibir la cadena a traducir y un botón para realizar la traducción:

<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/linearLayout1">
    <EditText android:id="@+id/etTextToTranslate"
    		  android:hint="hola mundo!"
    		  android:layout_width="wrap_content"
    		  android:layout_height="wrap_content"></EditText>
    <Button android:text="Traducir"
    		android:id="@+id/btnTranslate"
    		android:layout_width="wrap_content"
    		android:layout_height="wrap_content"></Button>
</LinearLayout>

Por último otro TextView que muestre el resultado.

<TextView android:id="@+id/txtTranslatedText"
		 android:layout_width="wrap_content"
		 android:layout_height="wrap_content"
		 android:textSize="20dp"></TextView>

Separamos de la siguiente sección a través de una línea horizontal:

<View
    android:layout_height="1dip"
    android:layout_width="fill_parent"
    android:background="#FFFFFF"
/>

Para la siguiente sección, la de búsqueda en YouTube de manera similar que el caso anterior indicamos al usuario a través de un TextView que debe ingresar el parámetro de búsqueda:

<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Ingrese texto a buscar en YouTube"
	/>

Luego, con otro LinearLayout horizontal que dentro tiene un EditText esperamos la cadena que será el parámetro de búsqueda y un botón para realizar la búsqueda:

<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/linearLayout2">
    <EditText android:id="@+id/etQueryText"
    		  android:hint="Android sdk"
    		  android:layout_width="wrap_content"
    		  android:layout_height="wrap_content"></EditText>
    <Button android:text="Buscar"
    		android:id="@+id/btnSearch"
    		android:layout_width="wrap_content"
    		android:layout_height="wrap_content"></Button>
</LinearLayout>

Terminamos con un ListView para mostrar el resultado de la búsqueda:

<ListView android:layout_height="wrap_content"
		  android:id="@+id/lstVideo"
		  android:layout_width="match_parent"></ListView>

El diseño completo queda de la siguiente forma:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Ingrese el texto a traducir"
	/>
	<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/linearLayout1">
	    <EditText android:id="@+id/etTextToTranslate"
	    		  android:hint="hola mundo!"
	    		  android:layout_width="wrap_content"
	    		  android:layout_height="wrap_content"></EditText>
	    <Button android:text="Traducir"
	    		android:id="@+id/btnTranslate"
	    		android:layout_width="wrap_content"
	    		android:layout_height="wrap_content"></Button>
	</LinearLayout>
	<TextView android:id="@+id/txtTranslatedText"
			 android:layout_width="wrap_content"
			 android:layout_height="wrap_content"
			 android:textSize="20dp"></TextView>
	<View
	    android:layout_height="1dip"
	    android:layout_width="fill_parent"
	    android:background="#FFFFFF"
	/>
	<TextView
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:text="Ingrese texto a buscar en YouTube"
	/>
	<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/linearLayout2">
	    <EditText android:id="@+id/etQueryText"
	    		  android:hint="Android sdk"
	    		  android:layout_width="wrap_content"
	    		  android:layout_height="wrap_content"></EditText>
	    <Button android:text="Buscar"
	    		android:id="@+id/btnSearch"
	    		android:layout_width="wrap_content"
	    		android:layout_height="wrap_content"></Button>
	</LinearLayout>
	<ListView android:layout_height="wrap_content"
			  android:id="@+id/lstVideo"
			  android:layout_width="match_parent"></ListView>
</LinearLayout>

Agregando código

Para el manejo de la respuesta de YouTube (en JSON) vamos a construir clases de Java que representen esta respuesta de tal forma que el proceso de parsing sea más sencillo. Estas clases serán internas y estáticas (más información en download.oracle.com) dentro de la clase de nuestra Activity principal.

Construiremos 3 clases:

Una para representar el resultado completo del request, una lista de ítems se llamará VideoFeed.

public static class VideoFeed {
  @Key List<Video> items;
}
      

Otra para representar cada ítem del resultado, del que nos interesa el título(atributo title) y el URL del video (atributo player contiene el URL por defecto y el móvil), se llamará Video. Esta clase además implementará el método toString para mostrar el título en un ListView más adelante.

public static class Video {
  @Key String title;
  @Key Player player;

  public String toString(){
	  return this.title;
  }
}
       

Una para representar el player utilizado en el caso anterior y que contiene la URL que vamos a utilizar para mostrar el video cuando el usuario haga click sobre el título se llamará: Player.

public static class Player {
	@Key String mobile;
}

La funcionalidad de la aplicación la trabajaremos dentro del método onCreate, en específico en el método onClick de Listeners asociados a los botones. Para la sección de traducción, primero le indicamos a Google desde que URL vamos a usar su API de Translate:

Translate.setHttpReferrer("www.ejemplo.com");

Luego, vamos a traer lo que ingresó el usuario en el EditText y escondemos el teclado para tener libre la pantalla para ver nuestra aplicación.

EditText etTextToTranslate = (EditText)findViewById(R.id.etTextToTranslate);
String textToTranslate = etTextToTranslate.getText().toString();
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(etTextToTranslate.getWindowToken(), 0);

Con esta cadena, usamos la librería para acceder al API de traducción indicando que el idioma fuente es español y el idioma objetivo es inglés.

String translatedText = Translate.execute(textToTranslate, Language.SPANISH, Language.ENGLISH);

Una vez recibida la respuesta, la mostramos al usuario en un TextView:

TextView txt = (TextView)findViewById(R.id.txtTranslatedText);
txt.setText(translatedText);

Para la sección de la búsqueda en YouTube iniciamos obteniendo el parámetro de búsqueda y ocultando el teclado.

EditText etQueryText = (EditText)findViewById(R.id.etQueryText);
String queryText = etQueryText.getText().toString();
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(etQueryText.getWindowToken(), 0);

Utilizando este parámetro de búsqueda, preparamos  el URL del request, indicamos que la respuesta la queremos en JSON y que la cantidad máxima de resultados será 5.

GenericUrl url = new GenericUrl("https://gdata.youtube.com/feeds/api/videos?alt=jsonc&amp;max-results=5&q=" + queryText);

Preparamos la requisición que requiere de transporte http y el parser de JSON:

HttpTransport transport = new NetHttpTransport();
final JsonFactory jsonFactory = new JacksonFactory();

Usando la instancia recién creada de HttpTransport, vamos a construir un RequestFactory indicándole el tipo de parser y los encabezados para el request.

HttpRequestFactory factory = transport.createRequestFactory(new HttpRequestInitializer() {
	@Override
	public void initialize(HttpRequest request) {
      	//indicamos el parser a utilizar
	    JsonCParser parser = new JsonCParser();
	    parser.jsonFactory = jsonFactory;
	    request.addParser(parser);

	    //indicamos el nombre de la aplicación y la versión de gData
     	  //JSON es soportado solo en versión 2 de gData
	    GoogleHeaders headers = new GoogleHeaders();
	    headers.setApplicationName("Maestros-Del-Web-Android/1.0");
	    headers.gdataVersion = "2";
	    request.headers = headers;
	}
});

Con los parámetros listos, construimos el request, lo ejecutamos y lo hacemos el parsing (reconocemos) indicando la clase VideoFeed previamente construida como resultado que deseamos.

HttpRequest request = factory.buildGetRequest(url);
final VideoFeed feed = request.execute().parseAs(VideoFeed.class);

El resultado guardado en esta variable feed (un listado de ítems Video) lo utilizaremos para construir un ArrayAdapter que luego se lo asociamos a nuestro ListView para poder visualizar el resultado en forma de listado en la aplicación.

ArrayAdapter<Video> adpList = new ArrayAdapter<Video>(
             getApplicationContext(),
             android.R.layout.simple_list_item_1,
             feed.items);

ListView videoList = (ListView)findViewById(R.id.lstVideo);
videoList.setAdapter(adpList);

Para finalizar, queremos que al presionar sobre el título de cualquier video del resultado podemos verlo, para esto hacemos uso del método setOnItemClickListener del ListView y en el método onItemClick obtenemos de la lista el elemento seleccionado y de él la URL móvil que tiene asociada. Con esta URL iniciamos una actividad que nos llevará a poder visualizar el video.

Video item = feed.items.get(position);
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(item.player.mobile)));

El código del método onCreate queda de la siguiente forma:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    Button btnTranslate = (Button) findViewById(R.id.btnTranslate);
    Button btnSearch = (Button) findViewById(R.id.btnSearch);

    btnTranslate.setOnClickListener(new OnClickListener() {
		@Override
		public void onClick(View v) {
	        Translate.setHttpReferrer("www.ejemplo.com");

	        try {
	        	EditText etTextToTranslate = (EditText)findViewById(R.id.etTextToTranslate);
	        	String textToTranslate = etTextToTranslate.getText().toString();

	        	InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
				imm.hideSoftInputFromWindow(etTextToTranslate.getWindowToken(), 0);

        		String translatedText = Translate.execute(textToTranslate, Language.SPANISH, Language.ENGLISH);
        		TextView txt = (TextView)findViewById(R.id.txtTranslatedText);
        		txt.setText(translatedText);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	});

    btnSearch.setOnClickListener(new OnClickListener() {
		@Override
		public void onClick(View v) {
        	EditText etQueryText = (EditText)findViewById(R.id.etQueryText);
    		String queryText = etQueryText.getText().toString();
			InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
			imm.hideSoftInputFromWindow(etQueryText.getWindowToken(), 0);

			HttpTransport transport = new NetHttpTransport();
		    GenericUrl url = new GenericUrl("https://gdata.youtube.com/feeds/api/videos?alt=jsonc&max-results=2&q=" + queryText);

		    final JsonFactory jsonFactory = new JacksonFactory();
		    HttpRequestFactory factory = transport.createRequestFactory(new HttpRequestInitializer() {
		      @Override
		      public void initialize(HttpRequest request) {
		        JsonCParser parser = new JsonCParser();
		        parser.jsonFactory = jsonFactory;
		        request.addParser(parser);

		        GoogleHeaders headers = new GoogleHeaders();
		        headers.setApplicationName("Maestros-Del-Web-Android/1.0");
		        headers.gdataVersion = "2";
		        request.headers = headers;
		      }
		    });

			try {
				HttpRequest request = factory.buildGetRequest(url);
			    final VideoFeed feed = request.execute().parseAs(VideoFeed.class);
			    ListView videoList = (ListView)findViewById(R.id.lstVideo);
			    ArrayAdapter<Video> adpList = new ArrayAdapter<Video>(getApplicationContext(),android.R.layout.simple_list_item_1,feed.items);
			    videoList.setAdapter(adpList);

			    videoList.setOnItemClickListener(new OnItemClickListener() {
					@Override
					public void onItemClick(AdapterView<?> arg0,
							View arg1, int position, long arg3) {
						Video item = feed.items.get(position);
						startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(item.player.mobile)));
					}
				});
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	});
}

Al ejecutar nuestra aplicación, probamos individualmente cada una de las 2 partes, primero la traducción

Luego la búsqueda en YouTube:

Descargar:

Puedes descargar el código de la aplicación completa y funcional en (github): Conectándonos con APIs de Google.

Conclusión

En este capítulo hemos aprendido a trabajar con 2 de los muchos APIs de google (http://code.google.com/more/table/) a través del uso de librerías desarrolladas por terceros. Para la parte de traducción utilizamos una librería específica (no olviden que este API está próximo a morir L http://code.google.com/apis/language/translate/overview.html) y para la parte de YouTube usamos una librería que permite conexión también a Latitude, Buzz, Books, Moderator y más (http://code.google.com/p/google-api-java-client/wiki/APILibraries)

Curso Android: son 10 capítulos ¿y qué hago ahora?

El objetivo del Curso Android era introducirte en el desarrollar para Android, pasamos de lo general (Activities, Intents, UI) a cosas más específicas (cámara, fotos, videos, mapas, sensores, servicios, emails y APIs) y que cada uno se lance a desarrollar con mucho entusiasmo.

Android sigue creciendo y junto a él los desarrolladores que apuestan por esta plataforma, no olviden seguir visitando @maestros para seguir aprendiendo sobre Android y sobre otras tecnologías que están marcando tendencias.