65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.33/5 (2投票s)

2008 年 8 月 4 日

CPOL

3分钟阅读

viewsIcon

29067

downloadIcon

169

端到端真实世界的黑莓应用程序演练,第 4 部分。

引言

在之前的三篇文章中,我一直在引导您创建一个端到端的黑莓应用程序,该应用程序将作为我的 知识库 示例 Web 应用程序的移动前端。

在本系列的 第三部分 中,我完成了应用程序中从设备内存存储和检索数据的区域。 与在设备上存储数据一样,使用网络对于大多数应用程序至关重要。 今天,我将向您展示应用程序将如何与其服务器端服务通信。

但首先,让我们进行一些重构。

选项类现在是 DataStore 类

是的,在使用 Options 类一段时间后,我决定,由于它不仅仅处理应用程序设置,因此更好的名称是 DataStore。“DataStore” 更好地解释了类的意图。

发出 HTTP 请求

关于 HTTP 连接的信息有很多。 我将把大部分内容省略在这篇文章中,只关注我们的应用程序能够发送 HTTP 请求和使用 HTTP 响应所绝对需要的内容。

我应该提到的两件事是 javax.microedition.io.HttpConnection 接口,它定义了 HTTP 连接所需的必要方法和常量,以及 javax.microedition.io.Connector,用于创建连接的工厂类。

对于我的网络任务,我重用了从现有的黑莓示例代码在线获取的一些代码,并对其进行了修改。 大部分的 HTTP 处理代码将符合在两个单独的接口(HTTPTransportHTTPTransportListener)中定义的契约。

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 将使用对请求的响应通知连接的 HTTPTransportListenerHTTPTransportListener 是一个接口,它定义了类为了处理来自 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);
}

测试网络代码

在这一点上,我需要能够在没有服务器端代码的情况下测试我的网络代码(它尚不存在)。 为了实现这一点,我构建了一个名为 MockHTTPTransportHTTPTransport 实现,它创建了不同类型的响应,以模拟在使用 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 请求,从数据库中检索信息,并将响应发送回黑莓设备上的应用程序。

之前的文章

© . All rights reserved.