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发布的,已经快两年没有更新了。