domingo, 14 de agosto de 2011

Utilizando Recursos con ClientBundle

¿Por qué utilizar ClientBundle para manejar recursos en mi aplicación?

Normalmente, una aplicación utiliza muchas imágenes. En HTML, cada imagen se almacena en un archivo separado y al navegador se le pide que descargue cada archivo desde el servidor web a través una transacción HTTP. Esta forma de manejar los recursos puede ser un desperdicio de varias formas:

  • Gastos innecesarios: En una aplicación convencional, por cada imagen se debe enviar una petición HTTP al servidor. A veces el tamaño de las imágenes es ínfimo (iconos o algo por el estilo). En ese caso, el tamaño de la imagen es a menudo más pequeña que la cabecera de la respuesta HTTP que se envía con los datos de imagen. Es decir, que la mayoría del tráfico es el contenido de los gastos generales que se requieren para obtener la imagen y no justamente de ella que sería lo normal.
  • Chequeos de cache innecesarios: Incluso cuando el cliente almacena en caché las imágenes, una solicitud 304 ("Not Modified") es enviada para comprobar y ver si la imagen ha cambiado. Dado que las imagenes cambian con poca frecuencia estos chequeos son innecesarios
     Todo esto hace que se retrase el inicio de nuestra aplicación. Es por eso que vamos a aprender como hacer uso de nuestras imagenes y estilos utilizando la interfaz ClientBundle.

     Supongamos que tenemos una aplicación básica de GWT y queremos llegar a algo como lo siguiente...


     ... utilizando estilos definidos en un css sobre los Labels y un par de imágenes como ejemplo.

     Lo primero que hay que hacer es crear el paquete "resources", dentro de este crear los paquetes "images" y "css". Dentro de este último ubicamos nuestra hora de estilos, en este ejemplo es "StylesCss.css". Dentro del paquete "images" ubicamos todas las imágenes que queremos utilizar dentro de nuestra aplicación.


        Nuestra hoja de estilos contiene algo como lo siguiente:

.crisStyle{
	color: blue;
	font-weight: bold;
	font-style: oblique;
	font-size: x-large;
}
.maxiStyle{	
	color: red;
	font-size: x-large;
}
.links{
	color: purple;
	text-decoration: blink;	
}

     Junto con la hoja de estilos vamos a crear la interfaz "StylesCss" donde vamos a mapear los estilos definiendo métodos que retornan un String.

package ar.com.gwt.test.client.resources.css;

import com.google.gwt.resources.client.CssResource;

/**
 * Styles CSS
 * @author Cristian N. Miranda
 */
public interface StylesCss extends CssResource{

	public String crisStyle();
	public String maxiStyle();
	public String links();
	
}

     Junto con las imágenes vamos a crear la interfaz "Images" mapeando las imágenes a utilizar:

/**
 * Images.java
 * @author Cristian N. Miranda
 */
package ar.com.gwt.test.client.resources.images;

import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;

public interface Images extends ClientBundle{

    @Source("arrow_refresh.png")
    public ImageResource refresh();

    @Source("accept.png")
    public ImageResource accept();
    
}

     Al nivel del paquete "resources" creamos la interfaz "Bundle" con el siguiente contenido:

package ar.com.gwt.test.client.resources;

import ar.com.gwt.test.client.resources.css.StylesCss;
import ar.com.gwt.test.client.resources.images.Images;
import com.google.gwt.resources.client.ClientBundle;

public interface Bundle extends ClientBundle {
	
    @Source("css/StylesCss.css")
    public StylesCss css();
    
    public Images images();
    
}

     Luego lo único que queda por hacer es inyectar los estilos desde la clase "Resources" la cual vamos a utilizar para acceder a los estilos y a las imágenes.

package ar.com.gwt.test.client.resources;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.StyleInjector;

public class Resources {

	public static Bundle instance = GWT.create(Bundle.class);

	static {
		StyleInjector.inject(instance.css().getText());
	}

}

   Ya estamos en condiciones de emplear los estilos e imágenes en donde queramos... por ejemplo, para conseguir el resultado esperado hacemos lo siguiente...
  
package ar.com.gwt.test.client;

import ar.com.gwt.test.client.resources.Resources;
import ar.com.gwt.test.client.resources.css.StylesCss;
import ar.com.gwt.test.client.resources.images.Images;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define onModuleLoad().
 */
public class GWTTest implements EntryPoint {
	
	public static StylesCss css = Resources.instance.css();
	public static Images images = Resources.instance.images();
	
	/**
	 * This is the entry point method.
	 */
	public void onModuleLoad() {
		
		HorizontalPanel words = new HorizontalPanel();
		HorizontalPanel main = new HorizontalPanel();
		VerticalPanel panel = new VerticalPanel();
		
		words.setSpacing(5);
		
		//Link to GWT Documentation
		Anchor a = new Anchor();
		a.setHref("http://somelink.com");
		a.setText("GWT Developer's Guide");
		a.setStyleName(css.links());
		
		//Labels
		Label maxiLabel = new Label("Using");
		maxiLabel.setStyleName(css.maxiStyle());
		
		Label crisLabel = new Label("Resources!");
		crisLabel.setStyleName(css.crisStyle());
		
		words.add(maxiLabel);
		words.add(crisLabel);
		
		//Images
		Image img1 = new Image(images.accept());
		Image img2 = new Image(images.refresh());
		
		main.add(panel);
		
		words.add(img1);
		words.add(img2);	
		
		panel.add(a);
		panel.add(words);
		
		RootPanel.get("mainContainer").add(panel);

	}
}

     Pueden descargar el ejemplo completo desde el siguiente link: http://code.google.com/p/gwt-client-bundle/downloads/list

2 comentarios:

  1. Hola,
    yo estoy haciendo algo parecido. Estoy intentando cargar un archivo html con client bundle. Tengo los siguientes códigos:


    package com.example.html.client;




    import com.google.gwt.core.client.GWT;
    import com.google.gwt.resources.client.ClientBundle;
    import com.google.gwt.resources.client.DataResource;
    import com.google.gwt.resources.client.ImageResource;
    import com.google.gwt.resources.client.TextResource;

    public interface Resources extends ClientBundle {


    public static final Resources INSTANCE = GWT.create(Resources.class);



    @Source("Images/P2.html")
    public TextResource getIntroHtml();
    }


    Y EL OTRO ES:

    package com.example.html.client;

    import com.example.html.shared.FieldVerifier;
    import com.google.gwt.core.client.EntryPoint;
    import com.google.gwt.user.client.ui.Grid;
    import com.google.gwt.user.client.ui.HTML;
    import com.google.gwt.user.client.ui.HTMLPanel;
    import com.google.gwt.user.client.ui.Image;
    import com.google.gwt.user.client.ui.Label;
    import com.google.gwt.user.client.ui.RootPanel;
    import com.google.gwt.user.client.ui.SimplePanel;
    import com.google.gwt.user.client.ui.Grid;



    public class Html implements EntryPoint {

    public void onModuleLoad()
    {



    HTML htmlPanel = new HTML();

    String html = Resources.INSTANCE.getIntroHtml().getText();
    htmlPanel.setHTML(html);



    /**
    * HTMLPanel dynContent = new HTMLPanel(Resources.INSTANCE.synchronous().getText());

    }

    }

    Pero a la hora de ejecutarlo no aparece por pantalla el archivo HTML.¿A qué puede ser debido?
    Gracias!

    ResponderEliminar
  2. Hola José!

    Gracias por pasar por el blog!

    No entiendo muy bien por que se da el problema.. El archivo HTML está bien estructurado?
    Igualmente creé un proyecto de ejemplo donde obtengo mediante Client Bundle el código HTML de una tal "page.html" y lo muestro en un HTML y un HTMLPanel.

    Link: http://www.mediafire.com/?9w5vou3onhk2jo2

    Espero sea de ayuda. Contme como fue.
    Saludos! :)

    ResponderEliminar