[J2ME]RSSOwlMidlet(RSS无线阅读器)设计说明
| 鄭昀@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://files.cnblogs.com/zhengyun_ustc/RSSOwlMidlet-src.rar
4:下載midlet:jad:?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年就已經通行天下了,最通常的是Blog的RSS輸出,當然許多其他類型的站點也都提供了本站內容的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:對記錄進行排序》的代碼,放棄了garrey的RecordComparator比較器的實現。
另外,在調試過程中,也加入了我的一些思考,以及兼容各種RSS的辦法。
?
總結一下特別之處。
特別是比原來Tommi?的版本增加了幾個特性:
l?????????最大的改動就是,原來Tommi把視圖/控制器都放在RssReaderMIDlet.java了,而我們將視圖分拆出來為RssFeedAdd.java、RssFeedEdit.java、RssFeedList.java等等,控制器則為GUIController.java;
l?????????可以添加/編輯/刪除Rss Feed書簽;
l?????????原來Tommi將Feed列表以及URL存儲在RMS的一個條目,我放棄了這種做法,而是像garrey處理電話記錄一樣;
l?????????當請求遠端服務器時,加入了動畫等候畫面,提示用戶正在獲取新聞列表;
l?????????由于采用了xmlpull方式解析XML,所以可以做到一邊后臺掃描XML文檔,一邊前臺將解析到的新聞Title顯示在用戶界面上,不影響用戶閱讀新聞列表;
l?????????兼容博客堂/博客園這種.Text類型Blog的RSS,因為它們限制請求方的“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。
Enhydra的KXML是一個被設計用于J2ME設備的只占很小存儲空間的XML語法分析程序,雖然它也可以被用于其它需要小型XML語法分析程序的環境,比如Applet。KXML支持以下特性:
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); //?設置null讓KXmlParser自動檢測該使用哪種編碼 |
?
其次,我們需要跳過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 <item> tags */ do { ????parser.require(parser.START_TAG, null, null);
? ????/** Initialize properties */ ????title = ""; ????description = ""; ????link = "";
? ????/** One <item> 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?????????Feed的URL,如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_getPage是false,那么本線程就只能先睡眠一段時間了. ????????????????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的。這樣會有問題。
?
后來看到KXML2的KXMLParser.java中setInput函數其實是可以自動處理編碼問題的:
| 代碼
|
| 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://files.cnblogs.com/zhengyun_ustc/RSSOwlMidlet-src.rar
4:下載midlet:jad:?RSSOwlMidlet.jad jar:?RSSOwlMidlet.jar?(jar包可能有點偏大,您可以進行混淆來縮小)
?
網絡資源:
1:How to create a J2ME MIDP RSS Reader application with NetBeans 4.0?作者?Tommi Laukkanen
2:J2ME手機電話本?作者?garrey
3:探索J2ME:對記錄進行排序
4:kxml2官方站點:http://kxml.sourceforge.net/
5:Xmlpull官方站點:http://www.xmlpull.org/
6:實例教您KXML:J2ME中XML語法分析的利器
?
?
| 編寫者 | 日期 | 關鍵詞 |
| 鄭昀@ultrapower | 2005-10-07 | RssReader RssFeed Channel j2me midp midlet kxml xmlpull RMS RssOwl java |
?
總結
以上是生活随笔為你收集整理的[J2ME]RSSOwlMidlet(RSS无线阅读器)设计说明的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android四大组件之Service
- 下一篇: 3.9 第二次作业