[J2ME]RSSOwlMidlet(RSS无线阅读器)设计说明

news/2024/6/18 2:28:03

 

郑昀@ultrapower

产品名称

产品版本

Keyword: RssReader RssFeed Channel j2me midp midlet  kxml xmlpull RMS RssOwl java

RSS无线阅读器

0.7.1729

[J2ME][开源]RSSOwlMidlet

(RSS无线阅读器)

设计说明

我的RssReader资源:

1[J2ME]RSSOwlMidlet(RSS无线阅读器)开源说明》

2[J2ME]RSSOwlMidlet(RSS无线阅读器)设计说明》

3:下载源代码:http://www.cnblogs.com/Files/zhengyun_ustc/RSSOwlMidlet-src.rar

4:下载midletjad: RSSOwlMidlet.jad jar: RSSOwlMidlet.jar (jar包可能有点偏大,您可以进行混淆来缩小)

摘要:

本文档给出RSS无线阅读器J2ME版本的设计思路和类说明。

1 简单描述RSS无线阅读器J2ME版本的背景、功能和特别之处

2 描述调用RSS无线阅读器J2ME版本的设计思路

3 给出了 RSS无线阅读器J2ME版本的设计过程中需要特别指出的问题

4 给出了 各种下载资源

 

1背景、功能和特别之处

摘要:本章 简单描述RSS无线阅读器J2ME版本的背景、功能和特别之处。

 

我们提供的RSS无线阅读器J2ME版本[开源]是一个可以下载到手机(例如Nokia7610)或者其他无线手持设备(例如PocketPC)的应用程序,用来阅读存在于Internet中广泛的RSS新闻源,比如

豆瓣最新评论 http://www.douban.com/feed/review/latest

博客堂 http://blog.joycode.com/MainFeed.aspx

博客园 http://www.cnblogs.com/rss.aspx

CSDN技术文档 http://www.csdn.net/Rss/RssFeed.aspx?rssid=3

ChinaUnix.net-业界新闻与评论 http://bbs.chinaunix.net/rss/46.xml

keso's blog http://feeds.feedburner.com/PlayinWithIt

等等,这些新闻源我们将预置在本应用程序中。

 

下面介绍RSS无线阅读器的功能列表:

l         RSS Feed列表

n         添加Rss Feed

n         编辑Rss Feed

n         删除Rss Feed

l         读取Rss Feed新闻

n         查看新闻摘要

l         重新读取Rss Feed新闻

l         关于我

 

1.1. RSS概念

这里简单介绍一下RSS,它并不是一个新概念,从大约2002年就已经通行天下了,最通常的是BlogRSS输出,当然许多其他类型的站点也都提供了本站内容的RSS输出格式,比如:

论坛帖子,比如“ChinaUnix.net

新闻站点,比如“百度新闻”或者“Google新闻”;

门户,比如“新浪体育”,等等。

 

RSS其实就是特定格式的XML。所以在J2ME解决方案中,就是通过HttpConnection获取RSS XML文档并解析,将新闻条目显示在界面上,说起来很简单的。

下面,我们说说这个应用程序的特别之处。

1.2. 特别之处

这个应用程序的思路来自于两个开源的应用程序:

How to create a J2ME MIDP RSS Reader application with NetBeans 4.0 作者 Tommi Laukkanen

J2ME手机电话本 作者 garrey

RSS读取以及用xmlpull解析这部分思路,采用了Tommi 的思路;

MVC的类分解,以及对RMS记录存储的封装模式,采用了 garrey 的思路。

 

对于获取RMS中存储的所有的Rss Feed列表,采用了文章《探索J2ME:对记录进行排序》的代码,放弃了garreyRecordComparator比较器的实现。

另外,在调试过程中,也加入了我的一些思考,以及兼容各种RSS的办法。

 

总结一下特别之处。

特别是比原来Tommi 的版本增加了几个特性:

l         最大的改动就是,原来Tommi把视图/控制器都放在RssReaderMIDlet.java了,而我们将视图分拆出来为RssFeedAdd.javaRssFeedEdit.javaRssFeedList.java等等,控制器则为GUIController.java

l         可以添加/编辑/删除Rss Feed书签;

l         原来TommiFeed列表以及URL存储在RMS的一个条目,我放弃了这种做法,而是像garrey处理电话记录一样;

l         当请求远端服务器时,加入了动画等候画面,提示用户正在获取新闻列表;

l         由于采用了xmlpull方式解析XML,所以可以做到一边后台扫描XML文档,一边前台将解析到的新闻Title显示在用户界面上,不影响用户阅读新闻列表;

l         兼容博客堂/博客园这种.Text类型BlogRSS,因为它们限制请求方的“User-Agent”;

l         采用KxmlParser的自动检测RSS XML文档的编码格式,所以不用用户专门设置编码格式。

 

2 设计思路

摘要:本章描述RSS无线阅读器J2ME版本的设计思路。

 

2.1. RSS XML读取及解析  

关键三个包:

l         javax.microedition.io. HttpConnection

l         org.kxml2.io. KXmlParser

l         org.xmlpull.v1.*

 

HttpConnection

下面来看看如何用HttpConnection类来请求远端的RSS服务器并获取RSS XML数据。

第一步是使用Connector类打开一个到服务器的连接,我们将把这个连接强制转换为需要的HttpConnection类型。

代码

HttpConnection hc = null;

hc = (HttpConnection) Connector.open( url );

hc.setRequestMethod(HttpConnection.GET);

 

接下来,我们得到HttpConnection上的一个InputStream,允许我们一个字符一个字符的读取服务器的响应数据。

代码

parseRssFeedXml( hc.openInputStream() );

 

public void parseRssFeedXml(InputStream is);

 

org.kxml2.io. KxmlParser

parseRssFeedXml函数就是负责用KXmlParser来解析这响应数据。

 

kxml2官方站点:http://kxml.sourceforge.net/

下载kxml2代码:http://sourceforge.net/project/showfiles.php?group_id=9157&package_id=58653

EnhydraKXML是一个被设计用于J2ME设备的只占很小存储空间的XML语法分析程序,虽然它也可以被用于其它需要小型XML语法分析程序的环境,比如AppletKXML支持以下特性:

1、支持XML名称空间

2、用"松散"模式分析HTML或其它SGML格式;

3、占用很少的存储空间(21 kbps

4、基于Pull的分析

5、支持XML写操作

6、可选的DOM支持

7、可选的WAP支持。

 

KXML支持DOM语法分析和操作,但是不支持push语法分析。取而代之,它使用一种稍微不同的称为“Pull”的分析方法。与push语法分析相反,Pull语法分析让程序员从语法分析程序中出下一个事件。

 

Xmlpull官方站点:http://www.xmlpull.org/

优点:不必等整个文档解析完成,部分求值结果早就可以开始反馈给用户。

 

下面我们看看KXML如何做一个Pull语法分析程序。

首先我们需要创建了一个XmlParser,并把它传到一个InputStream中。

代码

public void parseRssFeedXml(InputStream is)

            throws IOException, XmlPullParserException {

KXmlParser  parser = new KXmlParser();

parser.setInput( is, null); // 设置nullKXmlParser自动检测该使用哪种编码

 

其次,我们需要跳过RSS根节点的“rss”之类的东西。

代码

parser.nextTag();

parser.require(parser.START_TAG, null, null);

 

下面,我们来寻找RSS中的第一个“item”节点,它代表这个RSS文档中确实包含了新闻条目。这是通过下面的循环做到的。parser.next()的含义是“Get next parsing event”,这样就可以遍历文档,如果找不到item节点,就抛出一个异常。

代码

while(!"item".equals(parser.getName()) ){

    /** Check if document doesn't include any item tags */

    if( parser.next() == parser.END_DOCUMENT )

        throw new IOException("No items in RSS feed!");

}

 

确认有item节点后,我们来寻找RSS中代表每一个新闻的“item”节点下的三个节点“title”“link”“description”,这是通过下面的循环做到的。parser.next()的含义是“Call next() event if it is START_TAG or END_TAG otherwise throw an exception”,这样就可以遍历文档找全所有的新闻的主题、链接和摘要了。

代码

/** Parse tags */

do {

    parser.require(parser.START_TAG, null, null);

 

    /** Initialize properties */

    title = "";

    description = "";

    link = "";

 

    /** One tag handling*/

    while (parser.nextTag() != parser.END_TAG) {

        parser.require(parser.START_TAG, null, null);

        String name = parser.getName();

        String text = parser.nextText();

 

        /** Save item property values */

        if (name.equals("title"))

            title = text;

        else if (name.equals("description"))

            description = text;

        else if (name.equals("link"))

            link = text;

 

        parser.require(parser.END_TAG, null, name);

    }

 

    /** Create new RSS item and add it do RSS document's item

     *  collection

     */

    RssItem rssItem = new RssItem(title, link, description);

    m_rssFeed.getItems().addElement( rssItem );

             

    parser.nextTag();

   

} while("item".equals(parser.getName()));

 

2.2. MVC设计模式

划分为四个模块:

l         midlet

n         RssReaderMIDlet.java   

u       这当然是MIDlet必须的入口;它负责初始化控制器GUIController

l         Model,模型:

n         RssFeed.java

u       Rss Feed所对应的类实体,基本上有这么几个属性:

l         RMS中存储的id序号;

l         Feed名称,如“博客堂”或“博客园”;

l         FeedURL,如http://blog.csdn.net/zhengyun_ustc/Rss.aspx

n         RssFeedParser.java

u       获取RSS XML并解析的类

n         RssItem.java

u       对应于RSS Feed返回的每一个新闻条目的类实体,包含主题、摘要以及链接;

l         View,视图:

n         About.java

u       “关于我”的Alert界面

n         RssFeedAdd.java

u       “添加Rss Feed书签”的Form界面

n         RssFeedEdit.java

u       “编辑Rss Feed书签”的Form界面

n         RssFeedList.java

u       Rss Feed列表”的Form界面

n         RssFeedOpen.java

u       “读取Rss Feed新闻”的Form界面

n         RssFeedView.java

u       “查看Rss Feed书签”的Form界面

n         RssItemView.java

u       “查看新闻摘要”的Form界面

n         WaitFlash.java

u       “动画等待画面”的Canvas界面

l         controller

n         GUIController.java

u       MVC中的控制器部分,负责界面事件的处理,以及决定该显示哪一个Form

 

控制器的事件处理部分:

下面来看看如何处理界面事件。

代码

public void handleEvent( int eventID,Object[] args){  

           switch (eventID)

        {  

               case EventID.EVENT_EXIT:

               {

                            System.gc();     // 通知进行垃圾收集

                            Thread.yield();  // 本线程暂停一下,使得GC可以马上获得机会运行

                            rssMidlet.exit(false);

                      break;

               }

               case EventID.EVENT_VIEW_DETAIL:

               {

                            setCurrent(openForm);

                            openForm.setRss((RssFeed)args[0]);

                   break;

               }

……

 

每一个Form的如何转发事件:

每一个Form上也有事件响应,并可以自行处理事件,然后加入参数,进一步转发事件到控制器上。这个概念来自于garrey的手机电话本源代码。

代码

    /*

     * 内部监听器,监听器监听所有Command事件,并把事件响应推出来让控制器处理

     */

    private class RssFeedAddListener implements CommandListener{

              public void commandAction(Command command, Displayable disp){

                     if(command == BACK_COMMAND){

                            controller.handleEvent(GUIController.EventID.EVENT_NEW_BACK, null);

               }

                     else if(command == SAVE_COMMAND){

                   String title      =     titleField.getString();

                   String url              =     urlField.getString();

                   if((title == null || title.equals(""))

                                          || (url == null || url.equals("") || url.equals("http://"))){

                       return;

                   }

              

                            Object[] args = {title, url};

                            controller.handleEvent(GUIController.EventID.EVENT_NEW_SAVE, args);                                               

                     }//end else

              }

    }//end inner class

 

2.3. 读取新闻的后台线程问题

我们在RssFeedOpen这个“读取Rss Feed新闻”的Form界面中,做了一点特殊处理,这样才能够后台线程专门读取RSS XML,而前台界面只需要负责跟进显示解析出来的RSS新闻条目即可了。

所以我们的类这么声明:

代码

public class RssFeedOpen extends Form

                                          implements Runnable

 

我们为了实现,特地实现了一个run函数,它不断地循环查看标志m_getPage,如果是true,则说明后台线程应该去获取RSS XML了。否则,就睡眠一段时间。

代码

public void run(){

        /* Use networking if necessary */

        long lngStart;

        long lngTimeTaken;

        while(true) {

            try {

       //  我们是依靠m_getPage来判断是否去得到并解析Rss XML.

       //  如果当前m_getPagefalse,那么本线程就只能先睡眠一段时间了.

                if( m_getPage ) {

                    try {

        /** Get RSS feed */

              m_curRssParser.parseRssFeed();

              setCurrentDispalyToHeaderList();

                    }catch(Exception e) {                                    

                    }

                    m_getPage = false;

                }

                lngStart = System.currentTimeMillis();

                lngTimeTaken = System.currentTimeMillis() - lngStart;

                if(lngTimeTaken < 100)

                    m_netThread.sleep(75 - lngTimeTaken);

            } catch (InterruptedException e) {

                break;

            }

        }

    }

 

 

3 设计过程中需要特别指出的问题

摘要:本章给出了 RSS无线阅读器J2ME版本的设计过程中需要特别指出的问题。

 

3.2. HttpConnection请求博客堂/博客园问题

在请求Rss Feed时,遇到一个奇怪的问题。别的RSS源都没有问题,唯独博客堂/博客园始终返回这样的错误信息:

Bad Request (Invalid Header Name)

 

看来是HttpConnection请求时的Header设置问题。

最终经过反复试验,发现不能设置“User-Agent”字段,否则对方.Text应用不接受。

所以我把下面的代码注释:

hc.setRequestProperty("User-Agent",

            "Profile/MIDP-1.0 Configuration/CLDC-1.0");

3.3. 自动识别RSS XML编码问题

Tommi的代码中,是直接用:

parser.setInput( is,"utf-8"); // 设置读取用UTF-8编码

来解析XML的。这样会有问题。

 

后来看到KXML2KXMLParser.javasetInput函数其实是可以自动处理编码问题的:

代码

public void setInput(InputStream is, String _enc){

….

if (enc == null) {

                // read four bytes

 

                int chk = 0;

 

                while (srcCount < 4) {

                    int i = is.read();

                    if (i == -1)

                        break;

                    chk = (chk << 8) | i;

                    srcBuf[srcCount++] = (char) i;

                }

 

                if (srcCount == 4) {

                    switch (chk) {

                        case 0x00000FEFF :

                            enc = "UTF-32BE";

                            srcCount = 0;

                            break;

 

                        case 0x0FFFE0000 :

                            enc = "UTF-32LE";

                            srcCount = 0;

                            break;

 

                        case 0x03c :

                            enc = "UTF-32BE";

                            srcBuf[0] = '<';

                            srcCount = 1;

                            break;

 

                        case 0x03c000000 :

                            enc = "UTF-32LE";

                            srcBuf[0] = '<';

                            srcCount = 1;

                            break;

 

                        case 0x0003c003f :

                            enc = "UTF-16BE";

                            srcBuf[0] = '<';

                            srcBuf[1] = '?';

                            srcCount = 2;

                            break;

 

                        case 0x03c003f00 :

                            enc = "UTF-16LE";

                            srcBuf[0] = '<';

                            srcBuf[1] = '?';

                            srcCount = 2;

                            break;

 

 

 

4 资源

我的RssReader资源:

1《[J2ME]RSSOwlMidlet(RSS无线阅读器)开源说明

2《[J2ME]RSSOwlMidlet(RSS无线阅读器)设计说明

3:下载源代码:http://www.cnblogs.com/Files/zhengyun_ustc/RSSOwlMidlet-src.rar

4:下载midletjad: RSSOwlMidlet.jad jar: RSSOwlMidlet.jar (jar包可能有点偏大,您可以进行混淆来缩小)

 

网络资源:

1How to create a J2ME MIDP RSS Reader application with NetBeans 4.0 作者 Tommi Laukkanen

2J2ME手机电话本 作者 garrey

3探索J2ME:对记录进行排序

4kxml2官方站点:http://kxml.sourceforge.net/

5Xmlpull官方站点:http://www.xmlpull.org/

6:实例教您KXMLJ2MEXML语法分析的利器

 

 

编写者

日期

关键词

郑昀@ultrapower

2005-10-07

RssReader RssFeed Channel

j2me midp midlet

kxml xmlpull

RMS

RssOwl

java

 





http://www.niftyadmin.cn/n/3649624.html

相关文章

Android项目实战系列—基于博学谷(七)课程模块(上)

由于这个模块内容较多,分为上、中、下 三篇博客分别来讲述&#xff0c;请耐心阅读。 课程模块分为四个部分 课程列表 课程详情 视频播放 播放记录 课程模块&#xff08;上&#xff09;主要讲述课程列表部分 一、水平滑动广告栏界面 1、创建水平滑动广告栏界面 在res/layout文…

Android:安卓开发采用Volley网络框架+MySQL数据库,实现从服务器获取数据并展示完成记单词APP

一、功能与要求 实现功能&#xff1a;设计一个记单词APP。服务器采用Tomcat&#xff0c;数据库采用Mysql。实现用户的注册登录功能以及单词的增删改查。 指标要求&#xff1a;实现UI布局&#xff1b;将系统数据保存到Mysql数据库中&#xff0c;并采用Volley网络框架实现从服务…

Java基础---集合框架四(Map)

2015-4-19 一、Map集合 1、Map接口概述 将键映射到值的对象 一个映射不能包含重复的键 每个键最多只能映射到一个值 2、Map接口和Collection接口的不同 Map是双列的,Collection是单列的 Map的键唯一,Collection的子体系Set是唯一的 Map集合的数据结构值针对键有效&#xff0…

如何在GraphQL和Vue中构建文件处理应用

介绍 (Introduction) In this tutorial, we’ll go over how to handle file uploads in GraphQL by building a full-stack app. This tutorial will be divided into two main sections: building the GraphQL API, and creating the frontend app. The GraphQL API will be …

[J2ME]RSSOwlMidlet(RSS无线阅读器)开源说明

郑昀ultrapower产品名称产品版本Keyword: RssReader RssFeed Channel j2me midp midlet kxml xmlpull RMS RssOwl java RSS无线阅读器0.7.1729[J2ME][开源]RSSOwlMidlet(RSS无线阅读器)开源说明摘要&#xff1a;本文档给出RSS无线阅读器J2ME版本的开源说明。第1章 简单描述RSS…

Android项目实战系列—基于博学谷(七)课程模块(中)

由于这个模块内容较多,分为上、中、下 三篇博客分别来讲述&#xff0c;请耐心阅读。 课程模块分为四个部分 课程列表 课程详情 视频播放 播放记录 课程模块&#xff08;中&#xff09;主要讲述课程详情部分 一、课程详情界面 1、创建课程详情界面 在com.boxuegu.activity包中…

如何在JavaScript中使用解构分配

JavaScript provides you with the ability to destructure objects and assign the individual units in one take. This allows you to get to the point of what you want to do and keep things clean. JavaScript使您能够分解对象并一次性完成分配各个单元的功能。 这使您…

Java基础---集合框架二(ArrayList 接口)

2015-4-16 一、List集合 1、List集合特有方法 特有方法&#xff1a; voidadd(int index, E element) &#xff1a; 在当前集合中指定位置 添加给定的元素 Objectget(int index) 返回集合中指定位置的元素。 intindexOf(Object o)返回此集合中第一次出现的指定元素的索引&…