A. 前言
近期在Android上开发一个应用程序,需要解决前后端通信的问题。最常见的解决方案是使用HTTP+JSON,但个人感觉如果要传输多个数据项的话还是比较麻烦;另一个解决方案是Hessian;当然还有其它的解决方案,例如WebService等。这些方案都不够简单直接,后来找到Exadel Flamingo这个好东西,实际上它在Flex开发中用得比较多,有关于它在Android开发中使用的文章,在网上搜索到的并不多。
B. Exadel Flamingo简介
搞过Flex开发的人估计会听说过Exadel Flamingo,它是一个RIA的集成库和通信框架,可以实现前端(Flex, JavaFX和Android)和后端(JBoss Seam或Spring)的透明传输和远程调用,更多信息请访问官网。
C. 开发环境
- JDK 1.6.0_26
- JBoss AS 5.1.0.GA
- JBoss Seam 2.2.2.Final
- JBoss Tools 3.3.x
- Exadel Flamingo 2.2.0
- Android 2.3.3
- Eclipse 3.7.2
- Hessian 3.2.1
请先下载和安装好相关工具和库文件。
D. 服务器程序
1. 新建项目
打开Eclipse,新建一项目“Seam Web Project”,“Target runtime”选“JBoss 5.1 Runtime”。
2. 添加库文件
往/WebContent/WEB-INF/lib目录添加以下库文件:
flamingo-service-2.2.0.jar
flamingo-services-common-2.2.0.jar
hessian-3.2.1.jar
3. 修改配置
修改/WebContent/WEB-INF/web.xml,添加以下内容:
<servlet>
<servlet-name>Hessian Remote Servlet</servlet-name>
<servlet-class>com.exadel.flamingo.service.seam.HessianToSeamServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Hessian Remote Servlet</servlet-name>
<url-pattern>/flamingo/hessian/*</url-pattern>
</servlet-mapping>
它的作用是启用Flamingo的Servlet。
4. 编写代码
- 服务接口
package com.powercn.bridge.webremote;
public interface LoginService {
public String SERVICE_NAME = "login";
public boolean login(String username, String password);
public UserInfo getUserInfo(String username);
}
-
实体类
package com.powercn.bridge.webremote;
import java.io.Serializable;
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
private String username = "";
private String password = "";
private Integer money = 100;
public UserInfo(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
}
- 实现类
package com.powercn.bridge.impl;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import com.powercn.bridge.webremote.LoginService;
import com.powercn.bridge.webremote.UserInfo;
@Scope(ScopeType.STATELESS)
@Name(LoginService.SERVICE_NAME)
public class LoginServiceImpl implements LoginService {
public boolean login(String username, String password) {
if (password.equals("password")) {
return true;
} else {
return false;
}
}
public UserInfo getUserInfo(String username) {
UserInfo userInfo = new UserInfo(username);
userInfo.setPassword("password");
userInfo.setMoney(1000);
return userInfo;
}
}
E. 客户端程序
1. 新建项目
打开Eclipse,新建一项目“Android Project”,“Build Target”选“Android 2.3.3”。
2. 修改界面
双击/res/layout/main.xml,在布局编辑窗口里添加控件,最终形成以下布局。
3. 添加库文件
往/libs目录添加以下库文件,并在“Java Build Path”添加引用:
flamingo-android-common-2.2.0.jar
flamingo-android-hessian-client-2.2.0.jar
flamingo-java-client-2.2.0.jar
flamingo-service-2.2.0.jar
flamingo-services-common-2.2.0.jar
4. 复制代码
将服务器端的服务接口和实体类复制到src目录下的相同包名之下。
5. 编写代码
package com.powercn.bridge;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import com.bridge.android.R;
import com.exadel.flamingo.android.FlamingoApplication;
import com.powercn.bridge.webremote.LoginService;
import com.powercn.bridge.webremote.UserInfo;
public class MyClientActivity extends Activity {
private EditText serviceUrlEditText;
private EditText usernameEditText;
private EditText passwordEditText;
private Button loginButton;
private EditText logEditText;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
serviceUrlEditText = (EditText)findViewById(R.id.serviceUrlEditText);
usernameEditText = (EditText)findViewById(R.id.usernameEditText);
passwordEditText = (EditText)findViewById(R.id.passwordEditText);
loginButton = (Button)findViewById(R.id.loginButton);
logEditText = (EditText)findViewById(R.id.logEditText);
loginButton.setOnClickListener(onLoginClick);
// 要根据实际的情况修改IP地址和端口
serviceUrlEditText.setText("http://192.168.1.2:8080/my-server/flamingo/hessian");
}
private OnClickListener onLoginClick = new OnClickListener () {
public void onClick(View view) {
String serviceUrl = serviceUrlEditText.getText().toString();
// 初始化远程服务
FlamingoApplication flamingoApplication = (FlamingoApplication) getApplication();
flamingoApplication.initializeFlamingoServiceFactory(serviceUrl);
LoginService loginService = flamingoApplication.getService(LoginService.class, LoginService.SERVICE_NAME);
if (loginService == null) {
logEditText.append("初始化远程服务失败。\n");
return;
} else {
logEditText.append("初始化远程服务成功。\n");
}
// 调用远程方法,返回登录结果
String username = usernameEditText.getText().toString();
String password = passwordEditText.getText().toString();
boolean loginSucceed = loginService.login(username, password);
if (loginSucceed) {
logEditText.append("登录成功。\n");
} else {
logEditText.append("登录失败。\n");
}
// 调用远程方法,返回用户信息
UserInfo userInfo = loginService.getUserInfo(username);
logEditText.append("Username: " + userInfo.getUsername() + "\n");
logEditText.append("Password: " + userInfo.getPassword() + "\n");
logEditText.append("Money: " + Integer.toString(userInfo.getMoney()) + "\n");
}
};
}
F. 联调测试
发布my-server,启动JBoss,运行MyClient程序,一切顺利的话将会看到以下运行结果:
G. 注意问题
1. Hessian的版本
在线文档说用hessian-3.1.3.jar,exadel-flamingo-2.2.0附带文档说用hessian-4.0.6.jar。
实际运行时发现要使用hessian-3.2.1.jar,使用其它版本可能会出现异常,暂时没有时间细究原因。
版本低于3.2.1,前端Android程序出现异常: 06-09 14:34:16.918: E/AndroidRuntime(733): com.caucho.hessian.client.HessianConnectionException: 302:
版本高于3.2.1,后端JBoss应用会出现异常: 10:47:01,234 ALL [ContextSerializerFactory] java.lang.ClassNotFoundException: com.powercn.bridge.services.UserInfoHessianSerializer
2. 权限设置
要为客户端程序添加使用网络的权限,在AndroidManifest.xml加入:
<uses-permission android:name="android.permission.INTERNET"/>
3. 修改AndroidManifest.xml
application要配置为: android:name="com.exadel.flamingo.android.FlamingoApplication", 否则会出现异常: java.lang.ClassCastException。
4. JBoss设置
要在JBoss的设置界面的Server Behaviour组里,勾选 “Listen on all interfaces to allow remote web connections”,以允许其它主机访问。
5. 官方文档
在线文档的内容跟exadel-flamingo-2.2.0附带文档的内容略有不同,个人认为以附带文档为准。
6. 版本更新
Exadel Flamingo最后一个版本2.2.0,是在2010-07-23发布的,已经快两年没有更新了。