端到端真实世界 BlackBerry 应用,第四部分






4.33/5 (2投票s)
端到端真实世界的黑莓应用程序演练,第 4 部分。
引言
在之前的三篇文章中,我一直在引导您创建一个端到端的黑莓应用程序,该应用程序将作为我的 知识库 示例 Web 应用程序的移动前端。
在本系列的 第三部分 中,我完成了应用程序中从设备内存存储和检索数据的区域。 与在设备上存储数据一样,使用网络对于大多数应用程序至关重要。 今天,我将向您展示应用程序将如何与其服务器端服务通信。
但首先,让我们进行一些重构。
选项类现在是 DataStore 类
是的,在使用 Options
类一段时间后,我决定,由于它不仅仅处理应用程序设置,因此更好的名称是 DataStore
。“DataStore” 更好地解释了类的意图。
发出 HTTP 请求
关于 HTTP 连接的信息有很多。 我将把大部分内容省略在这篇文章中,只关注我们的应用程序能够发送 HTTP 请求和使用 HTTP 响应所绝对需要的内容。
我应该提到的两件事是 javax.microedition.io.HttpConnection
接口,它定义了 HTTP 连接所需的必要方法和常量,以及 javax.microedition.io.Connector
,用于创建连接的工厂类。
对于我的网络任务,我重用了从现有的黑莓示例代码在线获取的一些代码,并对其进行了修改。 大部分的 HTTP 处理代码将符合在两个单独的接口(HTTPTransport
和 HTTPTransportListener
)中定义的契约。
HTTPTransport 接口和 KbHTTPTransport 类
HTTPTransport
是一个接口,它定义了创建 HTTP 请求的方法。
/**
* Defines the methods to send HTTP requests.
*/
public interface HTTPTransport {
public void send(final String requestMethod,
final String URL, final String requestData);
public void send(final String requestMethod,
final String URL, final String requestData,
final String[] headerKeys, final String[] headerValues);
public void setHTTPTransportListener(HTTPTransportListener t);
public void removeHTTPTransportListener();
}
KbHTTPTransport
是一个辅助类,它可以通过实现 HTTPTransport
中定义的方法来发出 HTTP 请求。 KbHTTPTransport
将使用对请求的响应通知连接的 HTTPTransportListener
。 HTTPTransportListener
是一个接口,它定义了类为了处理来自 HTTP 请求的响应必须具有的方法。
在文章屏幕中实现 HTTPTransportListener
到目前为止,应用程序中唯一需要发送 HTTP 请求的地方是文章屏幕。 实现 HTTPTransportListener
允许我们的文章屏幕处理 HTTP 响应
public void processResponse(final int HTTPResponseCode, final String data) {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run()
{
switch (HTTPResponseCode) {
case (KbHTTPTransport.NOT_IN_COVERAGE):
Dialog.alert("Not in coverage.");
break;
case HttpConnection.HTTP_OK:
parseResponseData(data);
break;
// TODO: Check all the http error codes you are interested in.
// for example HttpConnection.HTTP_FORBIDDEN
default:
Dialog.alert("There was an error with the request.");
break;
}
}
});
}
选择传输格式
从通过网络传输序列化数据的多种格式(即 XML、二进制等)中,我决定以字符串的形式发送和接收数据,其中响应的内容是表示文章列表的自定义格式字符串。
格式化的文章列表将如下所示
id^~^title^~^dateCreated^~^author^~^tag1,tag2,...^~^contents~^~
其中序列 “^~^” 分隔文章的字段,序列 “~^~” 分隔一篇文章与下一篇文章。
请注意,这是一种非常简单的格式,既易于使用,又在传输的字符数方面很轻量级(想想 XML 有多冗长)。
parseResponseData()
例程是我们对响应字符串进行反序列化并创建 Article
实例列表的地方。
private void parseResponseData(String data) {
// Parse out each article from the string data
// Format: id^~^title^~^dateCreated^~^author^~^
//tag1,tag2,...^~^contents~^~<NEXT RECORD>
Vector articlesVector = new Vector();
int index = 0;
int length = data.length();
while (index != -1 && index < length - 1){
if (index == 0) index = -1;
Article article = new Article();
article.id = data.substring(++index ,
index = data.indexOf(FIELD_SEPARATOR, index));
index += 3;
article.title = data.substring(index ,
index = data.indexOf(FIELD_SEPARATOR, index));
index += 3;
article.dateCreated = data.substring(index,
index = data.indexOf(FIELD_SEPARATOR, index));
index += 3;
article.author = data.substring(index,
index = data.indexOf(FIELD_SEPARATOR, index));
index += 3;
String tags = data.substring(index,
index = data.indexOf(FIELD_SEPARATOR, index));
article.tags = StringUtilities.stringToWords(tags);
index += 3;
article.contents = data.substring(index,
index = data.indexOf(RECORD_SEPARATOR, index));
index += 2;
articlesVector.addElement(article);
}
articles = new Article[articlesVector.size()];
articlesVector.copyInto(articles);
articlesList.set(articles);
}
测试网络代码
在这一点上,我需要能够在没有服务器端代码的情况下测试我的网络代码(它尚不存在)。 为了实现这一点,我构建了一个名为 MockHTTPTransport
的 HTTPTransport
实现,它创建了不同类型的响应,以模拟在使用 HTTP 请求时可能发生的场景 - 超时、身份验证失败等。
class MockHTTPTransport implements HTTPTransport {
private HTTPTransportListener listener = null;
MockHTTPTransport() { }
public void setHTTPTransportListener(HTTPTransportListener t){
listener = t;
}
public void removeHTTPTransportListener(){
listener = null;
}
public void send(final String requestMethod, final String URL,
final String requestData){
send(requestMethod, URL, requestData, null, null);;
}
public void send(final String requestMethod, final String URL,
final String requestData, final String[] headerKeys,
final String[] headerValues) {
// Since this is just for testing purposes,
// in here we will return a list or articles,
// as if we had just gotten them via an http request.
createArticlesListResponse();
}
private void createArticlesListResponse() {
// Create the articles.
Article[] articles = new Article[15];
Article article;
for (int i = 0; i < 15; i++) {
article = new Article();
article.id = String.valueOf(i);
article.title = "Dummy article " + Integer.toString(i);
article.author = "doej";
article.contents = "This is a test article";
article.tags = new String[] {"tag 1", "tag 2", "tag 3"};
article.dateCreated = "01/01/2008";
articles[i] = article;
}
String FIELD_SEPARATOR = "^~^";
String RECORD_SEPARATOR = "~^~";
//Create the the simulated response data
//with the information from the articles.
StringBuffer response = new StringBuffer();
for (int i = 0; i < articles.length; i++) {
article = articles[i];
StringBuffer tags = new StringBuffer();
for (int j = 0; j < article.tags.length; j++) {
tags.append(article.tags[j] + ",");
}
// Remove the last ","
tags.deleteCharAt(tags.length() - 1);
// Format: id^~^title^~^dateCreated^~^author^~^
//tag1,tag2,...^~^contents~^~<NEXT RECORD>
response.append(article.id + FIELD_SEPARATOR +
article.title + FIELD_SEPARATOR +
article.dateCreated + FIELD_SEPARATOR + article.author +
FIELD_SEPARATOR + tags + FIELD_SEPARATOR + article.contents +
RECORD_SEPARATOR);
}
int httpResponseCode = HttpConnection.HTTP_OK;
// Introduce a delay to simulate latency.
try {
Thread.sleep(1500);
} catch (InterruptedException ex) {}
listener.processResponse(httpResponseCode,response.toString());
}
下一步
本系列的下一篇文章将专门介绍应用程序的服务器端。 在服务器端,我将把代码放在一起以处理传入的 HTTP 请求,从数据库中检索信息,并将响应发送回黑莓设备上的应用程序。