Facebook Twitter LinkedIn E-mail
magnify
Home 2012 七月

Vaadin Web应用开发教程(5):Vaadin Web应用的基本组成部分

上篇博客Vaadin Web应用开发教程(4):开始编写Web应用 介绍了一个最简单的Vaadin应用。一般来说,一个Vaadin应用由下面几个部分构成:

  • Windows  每个Web应用都有一个主窗口。主窗口(Main windows) 为应用程序级窗口,或是指UI层次的根元素。实际上Web应用可以包含多个应用程序级(application level)窗口,这些窗口都和Application对象关联。 每个根窗口还可以包含多个子窗口。
  • UI组件 ,每个应用的用户界面都由这些UI组件组合而成,用户通过这些UI组件和应用程序交互,用户通过UI组件触发事件,Web应用通过事件处理函数来响应用户。大部分的UI组件支持数据绑定。这些UI组件包括Label,Button,Checkbox等,程序员可以通过继承或组合来定义用户界面。
  • Events和Listener  Event为事件,Listener用来处理事件。
  • 资源 应用程序可以在页面上显示图像,超链接等,这些为资源文件,Vaadin支持多种资源种类。
  • 显示主题 Vaadin将UI显示的表述(Presentation)和逻辑(Logic)分开. 其中UI逻辑由对应的Java代码处理。而采用主题通过CSS来定义UI显示。Vaadin内置多种显示主题,开发人员也可自定义主题。
  • 数据绑定 Vaadin 定义了数据模型,使用这种数据模型,UI组件可以绑定到数据源,比如变量,数组,数据库的表。

主窗口

一般来说一个Vaadin Web应用只有一个主窗口(Main Windows)。 一般在Application对象中通过setMainWindow() 设置主窗口。

import com.vaadin.ui.*;

public class HelloWorld extends com.vaadin.Application {
    public void init() {
        Window main = new Window("The Main Window");
        setMainWindow(main);

        ... fill the main window with components ...     }}

定义了主窗口之后,可以通过主窗口的addComponent 为主窗口添加其它UI组件。这些UI组件将使用主窗口的缺省布局来排列UI组件,如果你需要使用其它布局方法,可以通过setContent()定义新的布局。

子窗口

Vaadin 的窗口有两种类型,一种为应用程序级(Application level)的窗口,如上面的主窗口,另外一种为子窗口,显示在某个应用程序级的窗口中。

子窗口的创建和关闭,子窗口也是Window对象,通过addWindow 添加到主窗口中,关闭子窗口是通过Application对象的removeWindow() 方法。

//open a window
mywindow = new Window("My Window");
mainwindow.addWindow(mywindow);
...
//close a window
myapplication.removeWindow (mywindow);

子窗口缺省可以通过右上方的关闭按钮关闭,可以通过将子窗口设为readonly禁止用户提供关闭按钮关闭子窗口。

可以通过setHeight, setWidth ,setPositionX,setPositionY 来设置窗口的大小和在屏幕的位置。

/* Create a new window. */
mywindow = new Window("My Dialog");
/* Set window size. */
mywindow.setHeight("200px");
mywindow.setWidth("400px");
/* Set window position. */
mywindow.setPositionX(200);
mywindow.setPositionY(50);

如果子窗口的大小为固定或者通过比例定义,当它显示的内容过大时,会自动出现滚动条。但如果子窗口某方向大小为定义时,则其大小会自动适应需显示的内容而不会出现滚动条。

Vaadin的窗口也支持所谓模式窗口,通常对话框显示为模式窗口。下图为一模式窗口,其父窗口为灰色显示:

事件处理

Vaadin 事件处理也是通过为UI组件添加Listener的方法来实现的,使用Listener有三种基本用法,下面以一个Button为例来说明这几种基本用法。

这里定义一个事件处理类来处理Button的Click事件

public class TheButton implements Button.ClickListener {
    Button thebutton;

    /** Creates button into given container. */
    public TheButton(AbstractComponentContainer container) {
        thebutton = new Button ("Do not push this button");
        thebutton.addListener(this);
        container.addComponent(thebutton);
    }

    /** Handle button click events from the button. */
    public void buttonClick (Button.ClickEvent event) {
        thebutton.setCaption ("Do not push this button again");
    }
}

一个应用中通常需要处理来自同一个类的多个UI对象触发的事件,比如多个Button,此时在Listener中需要区分事件是由哪个Button触发的。Vaadin支持多种方法来解决这个问题。一是通过event的getButton 方法,如下:

public class TheButtons implements Button.ClickListener {
    Button thebutton;
    Button secondbutton;

    /** Creates two buttons in given container. */
    public TheButtons(AbstractComponentContainer container) {
        thebutton = new Button ("Do not push this button");
        thebutton.addListener(this);
        container.addComponent(thebutton);

        secondbutton = new Button ("I am a button too");
        secondbutton.addListener(this);
        container.addComponent (secondbutton);
    }

    /** Handle button click events from the two buttons. */
    public void buttonClick (Button.ClickEvent event) {
        if (event.getButton() == thebutton)
            thebutton.setCaption("Do not push this button again");
        else if (event.getButton() == secondbutton)
            secondbutton.setCaption("I am not a number");
    }
}

第二种方法是使用addListener 的另外一个重载方法,这个方法可以将事件处理方法做为参数。如下例,参数类型为字符串,为事件处理函数的名称。

public class TheButtons2 {
    Button thebutton;
    Button secondbutton;

    /** Creates two buttons in given container. */
    public TheButtons2(AbstractComponentContainer container) {
        thebutton = new Button ("Do not push this button");
        thebutton.addListener(Button.ClickEvent.class, this,
                              "theButtonClick");
        container.addComponent(thebutton);

        secondbutton = new Button ("I am a button too");
        secondbutton.addListener(Button.ClickEvent.class, this,
                                 "secondButtonClick");
        container.addComponent (secondbutton);
    }

    public void theButtonClick (Button.ClickEvent event) {
        thebutton.setCaption ("Do not push this button again");
    }

    public void secondButtonClick (Button.ClickEvent event) {
        secondbutton.setCaption ("I am not a number!");
    }
}

第三种方法为匿名函数方法,这也是最简单的一种方法,无需定义新的类来处理事件。如下:

public class TheButtons3 {
    Button thebutton;
    Button secondbutton;

    /** Creates two buttons in given container. */
    public TheButtons3(AbstractComponentContainer container) {
        thebutton = new Button ("Do not push this button");

        /* Define a listener in an anonymous class. */
        thebutton.addListener(new Button.ClickListener() {
            /* Handle the click. */
            public void buttonClick(ClickEvent event) {
                thebutton.setCaption (
                        "Do not push this button again");
            }
        });
        container.addComponent(thebutton);

        secondbutton = new Button ("I am a button too");
        secondbutton.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                secondbutton.setCaption ("I am not a number!");
            }
        });
        container.addComponent (secondbutton);
    }
}

事件通常由系统触发,但也可以通过方法fireEvent 来触发某个事件。

 

Vaadin Web应用开发教程(4):开始编写Web应用

在前面Vaadin Web应用开发教程(2):安装开发环境 我们创建了一个Helloworld项目,现在回过头详细说明一个这个简单Web应用。

使用Eclipse Vaadin 插件创建项目,自动生成的项目目录如下:

可以看到,Vaadin库文件放在目录Webcontent/WEB-INF/lib 下,生成的Web应用主程序放在src 目录下,而部署描述文件web.xml 则放在Webcontent/WEB-INF目录下。

有Vaadin插件创建的初始Application 类定义如下:

package com.example.helloworld;

import com.vaadin.Application;
import com.vaadin.ui.*;

public class HelloworldApplication extends Application {
	@Override
	public void init() {
		Window mainWindow = new Window("Helloworld Application");
		Label label = new Label("Hello Vaadin user");
		mainWindow.addComponent(label);
		setMainWindow(mainWindow);
	}

}

所有的Vaadin Web应用都必须派生com.vaadin.Application 类作为Web应用的主入口。而派生类必须实现init 用于初始化工作(比如定义应用的主界面,设置应用的显示主题,访问Window对象等)。类Application提供的方法和Java Servlet 提供的API非常类似,但这只是个表象,Vaadin提供的Application类是很Session类相关的。实际上Application对象为一Session对象,因此上实现Vaadin编写Web 应用和使用Java SE Swing编写桌面应用非常相像。

Vaadin应用中运行是为运行在服务器端Servlet 容器中的一个HTTP Servlet ,下图为Vaadin Web应用程序的总体框架图:

应用的入口点为Application类,一般在Application的init方法中定义程序的UI,设置应用的显示主题,定义事件处理函数。UI控件可以通过数据绑定来操作数据的读写等。这和编写一般的桌面应用非常类似。

修改一下Application 的init 方法,添加一个按钮,点击这个按钮之后,显示当前时间。代码如下:

public class HelloworldApplication extends Application {
	@Override
	public void init() {
		final Window mainWindow = 
			      new Window("Myproject Application");

			   Label label = new Label("Hello Vaadin user");
			   mainWindow.addComponent(label);

			   mainWindow.addComponent(
			      new Button("What is the time?",
			         new Button.ClickListener() {
			         public void buttonClick(ClickEvent event) {
			            mainWindow.showNotification(
			               "The time is " + new Date());
			         }
			      }));  setMainWindow(mainWindow);
	}

}

 为应用定义UI ,首先创建一个根View,通常为Windows对象,然后创建其它UI组件,如Label,Button,通过addComponent 添加到windows 对象中(使用缺省的布局方法)。然后使用addListener 为Button添加按键处理方法。最后使用setMainWindow(mainWindow) 为应用设置主窗口。这和编写桌面应用没什么不同。开发人员无需了解底层的HTML, AJAX, JavaScript ,这些都有Vaadin库来管理。

运行结果如下:


 
编写测试应用之后,就是如何部署Web应用,由Vaadin编写的应用最后打包成单一的War文件,可以使用Tomcat或其它Application应用服务器直接部署这个war 文件。

web.xml 为部署描述文件,本例如下:

 <?xml version=”1.0″ encoding=”UTF-8″?>
<web-app id=”WebApp_ID” version=”2.4″
   xmlns=”http://java.sun.com/xml/ns/j2ee
   xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance
   xsi:schemaLocation=”http://java.sun.com/xml/ns/j2ee
   http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd“>
 <display-name>Helloworld</display-name>
 <context-param>
  <description>
  Vaadin production mode</description>
  <param-name>productionMode</param-name>
  <param-value>false</param-value>
 </context-param>
 <servlet>
  <servlet-name>Helloworld Application</servlet-name>
  <servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
  <init-param>
   <description>
   Vaadin application class to start</description>
   <param-name>application</param-name>
   <param-value>com.example.helloworld.HelloworldApplication</param-value>
  </init-param>
 </servlet>
 <servlet-mapping>
  <servlet-name>Helloworld Application</servlet-name>
  <url-pattern>/*</url-pattern>
 </servlet-mapping>
 <welcome-file-list>
  <welcome-file>index.html</welcome-file>
  <welcome-file>index.htm</welcome-file>
  <welcome-file>index.jsp</welcome-file>
  <welcome-file>default.html</welcome-file>
  <welcome-file>default.htm</welcome-file>
  <welcome-file>default.jsp</welcome-file>
 </welcome-file-list>
</web-app>
一般无需修改,后面将有详细描述。

使用Apache Tomcat部署Vaadin 应用的一般步骤如下:

1. 在Eclipse中使用File->Export->Web ->War File 生成 应用的打包文件. war 文件。

2. 使用tomcat 的控制台 ,缺省URL为 http://[web site]:8080

 

3. 使用tomcat 部署成功后,就可以使用http://[web url]:8080/[web app] 来访问这个Web应用。比如 http://www.guidebee.net:8080/sampler

4. 如果你不希望使用:8080 来访问这个应用,可以通过修改 apache 的配置文件 ,一般目录为 /etc/apache2/apache2.conf

   添加一行类似 ProxyPass /sampler http://www.guidebee.net:8080/sampler 

  然后你就可以用 http://www.guidebee.net/sampler 来访问这个Web应用了。

 

Vaadin Web应用开发教程(3):Vaadin应用程序框架介绍

Vaadin 应用程序框架为一服务器端技术,允许开发人员采用和开发桌面应用类似的方法开发Web应用。尽管Vaadin 底层采用了HTML,JavaScript,AJAX等Web技术,Vaadin应用程序框架很好的隐藏了这些细节,开发人员一般无需了解上述Web技术来开发Vaadin应用。

下图为Vaadin 总体结构图:

Vaadin 包含了一组Web 应用开发的API,大量的UI 组件,多种内置主题,以及数据绑定允许将数据源直接绑定到UI组件。

一个Vaadin应用实际为运行在Java Web服务器上的Serverlet,Vaadin的Terminal Adapter接受来自客户端浏览器发来的请求并解释用户事件(Event),Event 由UI组件发送给应用,应用通过Listener来响应用户事件。这和桌面应用非常类似。 如果应用程序需要修改UI显示,这是通过Terminal Adapter向浏览器发回响应(Response)来实现的。

所以Vaadin应用都由com.vaadin.Application派生。应用创建用户界面,响应用户事件等。

Vaadin应用程序框架的几个主要组成部分如下:

用户界面组件( User Interface Components)

包括界面布局(Layout),UI控件(如Button,Link,Lable等),和Swing提供的UI组件类似。Vaadin 的UI 组件由两部分组成:Client-Side 和 Server-Side。每个客户端部分对应一个服务器部分。他们之间通信通过Terminal Adapter来完成。

客户端引擎(Client-side Engine)

Vaadin的客户端引擎使用GWT(Google Web Toolkit)来渲染显示UI组件,它通过Terminal Aapater与服务器端UI组件部分通信。UI 变化使用UIDL(User Interface Definition Language)语言来描述。UIDL基于JSON表述。

终端适配器 (Terminal Adapter)

Vaadin 的UI组件不直接显示在网页上,而是通过终端适配器。有了这个额外的抽象层使得Vaadin应用可以运行于大部分的浏览器上。最新的Vaadin应用使用GWT来显示UI控件。UI组件向Terminal Adapter报告界面变化,当用户触发某个事件(比如点击按钮),这个事件由Client-Side Engine以AJAX请求的方法报告给服务器端的Terminal Adapter。服务端处理事件后再通过Terminal Adapter 以Response的方式返回给Client-Side Engine,从而进一步修改UI显示。

显示主题(Theme)

Vaadin将UI显示的表述(Presentation)和逻辑(Logic)分开. 其中UI逻辑由对应的Java代码处理。而采用主题通过CSS来定义UI显示。Vaadin内置多种显示主题,开发人员也可自定义主题。

用户界面定义语言(UIDL)

Terminal Adapter使用UIDL来描述UI控件及其变化。UIDL 本身通过JSON来描述。所有的UI变化,如Check 按钮选择与否的状态都是通过UIDL来描述的。

事件(Events)

用户交互触发事件,如鼠标按键,事件首先由Client-Side Engine处理,然后以HTTP请求的方式发送多到服务器,Terminal Adapter, 服务器端UI组件部分等。

数据模型(Data Model)

Vaadin 定义了数据模型,使用这种数据模型,UI组件可以绑定到数据源,比如变量,数组,数据库的表。

 

 

Vaadin Web应用开发教程(2):安装开发环境

Vaddin支持多种开发环境,如Eclipse,NetBean等,这里使用Eclipse开发环境,也是最常用的Vaddin开发环境。 这里假定你对开发Java程序有一定的了解,对Eclipse开发也比较熟悉。如果你在做Android开发,希望开发一些Client/Server的Android应用,Vaddin是一个比较好的选择,Vaddin使用纯Java开发环境,也使用EclipseIDE,可以用来开发服务器端应用。

Vaddin 开发环境使用如下工具:

1. 安装Eclipse Java EE 版  http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/junor

2.   安装Vaadin 插件

  1. 启动 Eclipse.
  2. 选择菜单 Help → Software                    Updates….
  3. 选择 the Available Software tab.
  4. 添加Vaadin 插件URL http://vaadin.com/eclipse

    .

选择Vaadin 插件,然后安装.

下面来创建一个Hello World 项目,如果你的项目能正确运行,说明你安装好Vaadin开发环境。

1.  创建新Project  -> Vaadin -> Vaadin Project

项目名称:Helloworld,  其它使用缺省值,Vaadin 当前版本为 6.8.1 , 如果你没有下载,可以选择Download ,自动下载到本地。

点击“Finish”,完成新项目的创建。

2.  运行 这个项目,在项目浏览器中选择Helloworld, 点击右键,选择 Run As ->Run on Server,

如果你第一次运行Vaadin项目,可能需要创建一个服务器实例,提供选择Manually define a new server ,如果你希望使用Tomcat作为服务器测试环境,可以选择”Download additional server adapters” 然后选择下载Apache Geronimo V3.0 server.  然后选择你要使用的Tomcat 版本,最新的版本为Tomcat 7. 你可以使用”Download and Install” 自动下载Tomcat到本地:

3. 修改HelloworldApplication.java 代码如下:

public class HelloworldApplication extends Application {
@Override
public void init() {
Window mainWindow = new Window(“Helloworld Application”);
Label label = new Label(“Hello world“);
mainWindow.addComponent(label);
setMainWindow(mainWindow);
}

}

如果你可以得到如下结果,就表示你Vaadin环境安装成功:

注: 你可能需要在url 后面加上?restartApplication 通知Vaddin /Tomcat使用新编译的代码。

后面将逐步详细介绍Vaadin开发。

 

Vaadin Web应用开发教程(1):概述

Vaddin 是一个Web应用程序框架,用其开发的浏览器应用界面可以达到和桌面应用类似的效果,但和Flash  ,Silverlight不同的是,Vaddin应用无需再浏览器上安装任何插件。它是一个纯Java开发环境,开发人员无需深入了解HTML,XML或是Javascipt。如果你曾经使用Java开发过Swing,SWT等应用,可以非常容易开始使用Vaddin开发Web应用。

下表为Vaddin 应用程序框架和其它一些应用程序框架的比较:

Vaddin 应用程序框架具有如下特点:

  • Comprehensive Component Framework

提供大量的UI控件,支持托放,支持移动设备(触摸事件),数据绑定MVC,支持代码或HTML定义界面。支持自定义控件等。

  • Web Compatibility

Vaddin UI控件基于GWT,因此具有很好的浏览器兼容性,无需安装浏览器插件。支持分页,回退按键,支持URL参数等。

  • Customizable Look and Feel

很好的CSS支持,多种内置Theme和Style,并可以自定义主题和风格。

  • Java Web Development

纯Java开发环境,强大的服务器端技术开发模式,部署只需单个Jar文件,兼容多种Java虚拟机。

  • Secure Web Application Architecture

服务器端状态管理,应用程序代码运行在服务器端,内置输入校验,安全请求检测等。

  • Extensible Component Architecture

支持GWT扩展,提供多种插件以满足应用程序开发需求。

  • Tools

支持多种开发环境如Eclipse, Netbean, Maven 并提供Vaadin TestBench测试框架。

  • Deployment

支持JSR154 Java EE Sevlet 2.3+ 部署框架。 支持JSR 168,JSR286 Portlet部署。支持Google App Engine部署。

最后看看 Vaadin提供的Sampler的界面。在线演示

部分截图如下:

 

Android RoboGuice2 使用指南(4): 综合示例Astroboy

前面介绍了RogoGuice2.0的基本用法,其它使用可以参见RoboGuice1.1开发指南,2.0中提供了对Fragment,View(自定义View中使用注入)的支持,本博客不再一一介绍。

本例使用的是RoboGuice 开发包中的简单示例Astroboy(阿童木)。涉及的使用RoboGuice2.0 的一些常用方法。

本例下载(Eclipse项目)。

下面对项目中RoboGuice2的使用进行解释。因为本例没使用自定义绑定,所以无需使用res/values/roboguice.xml 定义Module. 如有自定义模块,可以参见Android RoboGuice2 使用指南(2): 第一个例子Hello World

1. 类Astroboy

// There's only one Astroboy, so make it a @Singleton.
// This means that there will be only one instance of Astroboy in the entire
// app.
// Any class that requires an instance of Astroboy will get the same instance.
// This also means this class needs to be thread safe, of course
@Singleton
public class Astroboy {

	// Because Astroboy is a Singleton, we can't directly inject the current
	// Context since the current context may change depending on what activity
	// is using Astroboy
	// at the time. Instead we use the application context.
	// Vibrator is bound to context.getSystemService(VIBRATOR_SERVICE) in
	// DefaultRoboModule.
	// Random has no special bindings, so Guice will create a new instance for
	// us.
	@Inject	Application application;
	@Inject	Vibrator vibrator;
	@Inject	Random random;

	public void say(String something) {
		// Make a Toast, using the current context as returned by the Context
		// Provider
		Toast.makeText(application, "Astroboy says, \"" + something + "\"",
				Toast.LENGTH_LONG).show();
	}

	public void brushTeeth() {
		vibrator.vibrate(
				new long[] { 0, 200, 50, 200, 50, 200, 50, 200, 50, 200, 50,
						200, 50, 200, 50, 200, 50, 200, 50, 200, 50, 200, 50, },
				-1);
	}

	public String punch() {
		final String expletives[] = new String[] { "POW!", "BANG!", "KERPOW!",
				"OOF!" };
		return expletives[random.nextInt(expletives.length)];
	}
}

程序中只希望使用一个Astroboy实例,因此可以使用@Singleton标注,此后任何使用

@Inject Astroboy astroboy;

注入的Astroboy都会指向同一个实例,这也是符合Singleton设计模式的。

@Inject Application application; 注入Application实例。参见Android RoboGuice 使用指南(15):Inject Context

@Inject Vibrator vibrator; 注入Android Vibrator实例,参见Android RoboGuice 使用指南(16):Standard Injection

@Inject Random random; 对于普通的Java 类型(POJO),如果该类具有缺省构造函数(不带参数的等),也可以使用RoboGuice自动注入实例。

因此当Astroboy创建时,RoboGuice 自动为application, vibrator, random 创建实例,无需使用new 或参数传入来构造它们。

2. 类AstroboyRemoteControl

/**
 * A class to control Astroboy remotely.
 *
 * This class uses the current context, so we must make it @ContextSingleton.
 * This means that there will be one AstroboyRemoteControl for every activity or
 * service that requires one. Note that we actually ask for the Activity, rather
 * than the Context (which is the same thing), because we need access to some
 * activity-related methods and this saves us from having to downcast to an
 * Activity manually.
 *
 * It also asks RoboGuice to inject the Astroboy instance so we can control him.
 *
 * What you'll learn in this class - What @ContextScope means and when to use it
 * - How to inject an Activity instead of a Context (which is really the same
 * thing) - How to use RoboGuice's convenient and flexible logging facility, Ln.
 */
@ContextSingleton
public class AstroboyRemoteControl {

	// The Astroboy class has been decorated with @Singleton, so this instance
	// of Astroboy will be the same instance used elsewhere in our app.
	// Injecting an Activity is basically equivalent to "@Inject Context context",
	// and thus also requires @ContextScope. If you wanted, you could also
	// @Inject Application, Service, etc. wherever appropriate.
	@Inject	Astroboy astroboy;
	@Inject	Activity activity;

	public void brushTeeth() {
		// More info about logging available here:
		// http://code.google.com/p/roboguice/wiki/Logging
		Ln.d("Sent brushTeeth command to Astroboy");
		astroboy.brushTeeth();
	}

	public void say(String something) {
		Ln.d("Sent say(%s) command to Astroboy", something);
		astroboy.say(something);
	}

	public void selfDestruct() {
		Toast.makeText(
				activity,
				"Your evil remote control has exploded! Now Astroboy is FREEEEEEEEEE!",
				Toast.LENGTH_LONG).show();
		activity.finish();
	}
}

与Singleton类似的一个Scope标注为@ContextSingleton ,它表示对于每个Activity实例有一个实例,不同的activity对应不同的实例。

@Inject Astroboy astroboy; 注入同一个Astroboy实例(Singleton)。

@Inject Astroboy astroboy; 注入对应的Activity实例。

3. 类AstroboyMasterConsole

/**
 * This activity uses an AstroboyRemoteControl to control Astroboy remotely!
 *
 * What you'll learn in this class: - How to use @InjectView as a typesafe
 * version of findViewById() - How to inject plain old java objects as well
 * (POJOs) - When injection happens - Some basics about injection, including
 * when injection results in a call to an object's default constructor, versus
 * when it does something "special" like call getSystemService()
 */
@ContentView(R.layout.main)
public class AstroboyMasterConsole extends RoboActivity {

	// Various views that we inject into the activity.
	// Equivalent to calling findViewById() in your onCreate(), except more
	// succinct
	@InjectView(R.id.self_destruct)	Button selfDestructButton;
	@InjectView(R.id.say_text)	EditText sayText;
	@InjectView(R.id.brush_teeth)	Button brushTeethButton;
	@InjectView(tag = "fightevil")	Button fightEvilButton; // we can also use tags if we want

	// Standard Guice injection of Plain Old Java Objects (POJOs)
	// Guice will find or create the appropriate instance of AstroboyRemoteControl for us
	// Since we haven't specified a special binding for AstroboyRemoteControl,
	// Guice will create a new instance for us using AstroboyRemoteControl's default constructor.
	// Contrast this with Vibrator, which is an Android service that is
	// pre-bound by RoboGuice.
	// Injecting a Vibrator will return a new instance of a Vibrator obtained by
	// calling
	// context.getSystemService(VIBRATOR_SERVICE). This is configured in
	// DefaultRoboModule, which is
	// used by default to configure every RoboGuice injector.
	@Inject	AstroboyRemoteControl remoteControl;
	@Inject	Vibrator vibrator;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState); // @Inject, @InjectResource, and
											// @InjectExtra injection happens
											// during super.onCreate()

		sayText.setOnEditorActionListener(new OnEditorActionListener() {
			public boolean onEditorAction(TextView textView, int i,
					KeyEvent keyEvent) {

				// Have the remoteControl tell Astroboy to say something
				remoteControl.say(textView.getText().toString());
				textView.setText(null);
				return true;
			}
		});

		brushTeethButton.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				remoteControl.brushTeeth();
			}
		});

		selfDestructButton.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {

				// Self destruct the remoteControl
				vibrator.vibrate(2000);
				remoteControl.selfDestruct();
			}
		});

		// Fighting the forces of evil deserves its own activity
		fightEvilButton.setOnClickListener(new OnClickListener() {
			public void onClick(View view) {
				startActivity(new Intent(AstroboyMasterConsole.this,
						FightForcesOfEvilActivity.class));
			}
		});

	}

}

AstroboyMasterConsole 为主Activity,要使用RoboGuice,则Activity需从RoboActivity派生,其它如Service,Fragment等可以参见Android RoboGuice 使用指南(13):RoboGuice 功能描述

@InjectView(R.id.self_destruct) Button selfDestructButton;  注入View实例,功能同findViewById。 它的另外一种方法是使用Tag,如

@InjectView(tag = “fightevil”) Button fightEvilButton ,功能一样。

这个类使用@ContentView(R.layout.main) 为Activity指明ContentView,无需再调用setContentView.

4. 类FightForcesOfEvilActivity

/**
 * Things you'll learn in this class: - How to inject Resources - How to use
 * RoboAsyncTask to do background tasks with injection - What it means to be a @Singleton
 */
public class FightForcesOfEvilActivity extends RoboActivity {

	@InjectView(R.id.expletive)	TextView expletiveText;

	// You can also inject resources such as Strings, Drawables, and Animations
	@InjectResource(R.anim.expletive_animation)	Animation expletiveAnimation;

	// AstroboyRemoteControl is annotated as @ContextSingleton, so the instance
	// we get in FightForcesOfEvilActivity will be a different instance than
	// the one we got in AstroboyMasterConsole
	// @Inject AstroboyRemoteControl remoteControl;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.fight_evil);

		expletiveText.setAnimation(expletiveAnimation);
		expletiveAnimation.start();

		// Throw some punches
		for (int i = 0; i < 10; ++i)
			new AsyncPunch(this) {
				@Override
				protected void onSuccess(String expletive) throws Exception {
					expletiveText.setText(expletive);
				}

				// We could also override onException() and onFinally() if we
				// wanted

			}.execute();

	}

	// This class will call Astroboy.punch() in the background
	public static class AsyncPunch extends RoboAsyncTask<String> {

		// Because Astroboy is a @Singleton, this will be the same
		// instance that we inject elsewhere in our app.
		// Random of course will be a new instance of java.util.Random, since
		// we haven't specified any special binding instructions anywhere
		@Inject	Astroboy astroboy;
		@Inject	Random random;

		public AsyncPunch(Context context) {
			super(context);
		}

		public String call() throws Exception {
			Thread.sleep(random.nextInt(5 * 1000));
			return astroboy.punch();
		}
	}
}

@InjectResource(R.anim.expletive_animation) Animation expletiveAnimation; 注入资源,可以参见Android RoboGuice 使用指南(18):Inject Resources

从代码中可以看出使用RoboGuice 注入可以简化程序,运行结果如下图: