版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
RSSReaderXMLOPhone平台开发2009-11-30:RSSReaderXML现在,我们在RSSReader中已经实现了通过ListView显示Item,通过多线程实现联网,通过Asynk异步更新UI,下面,我们需要将联网的RSS内容解析出来,变成一个简单的List,然后交给ListView显示出来,就可以实现一个最基本的RSSReader了。由于RSS的内容是标准的XML,因此,我们目前的任务是解析XML。从网络的RSS都是XML格式,因此,需要将其解析为简单的JavaBean。在OPhone应用中,解析XMLJava5API是DOMSAX。使用DOM解析XML时,需要将整个XML以DOM树的结构解析到内存,这将占用巨大的内存空间,对于这样的手持设备而言非常不合适,因此,在OPhone应用程序中要尽可能地不使用DOM。SAX则是由驱动的XML解析方式,通过各种节点,就可以将XML中感的数据解析出来。由于SAX不会把XML解析到内存,所以,它占用的内存比DOM要少得多,在OPhone应用SAX解析XML是最佳选择。在RSSReaderSAX解析XML的逻辑主要放在FeedParser和FeedParserHandler中。通过处理SAX的starement()、endElement()和characters()这3个,我们可以根据我们关心的节点名称提取一个Feed的title、description和每个item项的内容。通过FeedParserListener,在解析XML的过程中,可以获得相应的数据:目前的XMLFeed主要有RSS和ATOMRSS<?xmlversion='1.0'encoding='UTF-8'?><rss><channel><title>feedtitle</title><description>feedsubtitle</description><item><pubDate>Fri,11Sep2009 </pubDate>title</title><description>post<link></link><author>nameofauthor</author><item>...item...</item></channel>而ATOM<?xmlversion='1.0'encoding='UTF-8'?><feed><title>feedtitle</title><subtitle>feedsubtitle</subtitle><entry><published>2009-09-11T17:11:00.005+08:00</published><title>posttitle</title><content>postcontent</content><linkhref=''/><author><name>nameofauthor</name></author></entry><entry>..entry...</entry>为了能同时处理这两种格式的FeedSAX解析所必需的Handler,从org.xml.sax.helpers.DefaultHandler派生FeedParserHandler如下:classFeedParserHandlerextendsDefaultHandler{staticfinalintTYPE_UNKNOWN=0;staticfinalintTYPE_RSS=1;staticfinalintTYPE_ATOM=2;staticfinalStringNODE_RSS_TITLE="title";staticfinalStringNODE_RSS_DESCRIPTION="description";staticfinalStringNODE_RSS_LINK="link";staticfinalStringNODE_RSS_PUBDATE="pubDate";staticfinalStringNODE_RSS_AUTHOR="author";staticfinalStringNODE_RSS_CREATOR="dc:creator";staticfinalStringNODE_ATOM_TITLE="title";staticfinalStringNODE_ATOM_SUBTITLE="subtitle";staticfinalStringNODE_ATOM_CONTENT="content";staticfinalStringNODE_ATOM_PUBLISHED="published";staticfinalStringNODE_ATOM_AUTHOR_NAME="name";staticfinalSet<String>fetchChars=newHashSet<String>();static{fetchChars.add(NODE_RSS_TITLE);fetchChars.add(NODE_RSS_DESCRIPTION);fetchChars.add(NODE_RSS_LINK);fetchChars.add(NODE_RSS_AUTHOR);fetchChars.add(NODE_RSS_CREATOR);fetchChars.add(NODE_RSS_PUBDATE);fetchChars.add(NODE_ATOM_TITLE);fetchChars.add(NODE_ATOM_AUTHOR_NAME);}privatefinalFeedParserListenerlistener;privatebooleanfeedTitleLoaded=false;privatebooleanfeedDescriptionLoaded=false;privateinttype=TYPE_UNKNOWN;privatebooleanfirs ement=true;privateFeedItemcurrentItem=null;privateStringBuildercache=newStringBuilder(4096);}成员变量type指示Feed的类型为UNKNOWN、RSS和ATOM这3种类型之一,配合firs使用,根据XML的第一个确定Feed的类型,响应starement()@Overridepublicvoidstarement(Stringuri,StringlocalName,StringqName,Attributesattributes)throwsSAXException{if(firsement){if("rss".equals(localName))type=TYPE_RSS;elseif("feed".equals(localName))type=TYPE_ATOM;elsethrownewSAXException("Unknowntype'<"+localName+">'.");firsement=false;return;}}成员变量currentItem用于当前的<item>节点(RSS格式)或<entry>节点(ATOM格式),if(type==TYPE_RSS&&"item".equals(localName)){currentItem=newFeedItem();return;}elseif(type==TYPE_ATOM&&"entry".equals(localName)){currentItem=newFeedItem();return;}在endElement()中,遇到<item>节点(RSS格式)或<entry>节点(ATOM格式)时,检@OverridepublicvoidendElement(Stringuri,StringlocalName,StringqName)throwsSAXException{if((type==TYPE_RSS&&"item".equals(localName))||(type==TYPE_ATOM&&"entry".equals(localName))){checkItem(currentItem);listener.onItemLoad(currentItem);currentItem=null;return;}}成员变量cache用于缓存当前节点文本,当遇到我们感的节点时,初始化cache,以便在@Overridepublicvoidstarement(Stringuri,StringlocalName,StringqName,Attributesattributes)throwsSAXException{...if(fetchChars.contains(localName))cache=newStringBuilder(1024);elsecache=null;}@Overridepublicvoidcharacters(char[]ch,intstart,intlength)throwsSAXException{if(cache!=null)cache.append(ch,start,length);}请注意:一个节点的文本可能多次characters(),因此,我们需要通过StringBuilder来记录文本,尽管大多数时候一个节点只一次characters()。通过Listener机制,客户端就可以传入一个Listener来Feed的解析。最后,整个解析功能封装到FeedParser的parse()方法中:publicvoidparse(InputStreaminput,FeedParserListener{FeedParserHandlerhandler=newFeedParserHandler(listener);{SAXParserparser=saxParserFactory.newSAXParser();parser.parse(input,handler);}catch(SAXExceptione){thrownewRuntimeException(e);}catch(IOExceptione){thrownewRuntimeException(e);}catch(ParserConfigurationExceptione){thrownewRuntimeException(e);}finally{if(input!=null){try{input.close();}catch(IOExceptione){}}}SAX解析时,输入的XML可以是String、byte[]、InputStream、Reader等多种类型,这里我们使用InputStream是因为可以直接把HttpConnection的InputStream传入,不必再缓存从网络的XML内容。使用IE8或Firefox3浏览器时,用户会注意到,当浏览一个含有RSS订阅源的页面时(例如,博客首页),浏览器的地址栏会自动提示用户可以订阅该页面的RSS。这个功能其实不是浏览器提供的,而是在HTML源码中RSS,其他应用程序(包括浏览器)就能够从页面中提取RSS源。一个Feed<linkrel="alternate"type="application/rss+xml"href="/liaoxuefeng"或者用ATOM<linkrel="alternate"type="application/atom+xml"其中,type类型“application/rss+xml”这是一个RSS格式的Feed,而类型“application/atom+xml”这是一个Atom格式的Feed。通过扫描HTML中包含的<link>FeedRSSReader必须能够提取包含在HTML页面中的Feed,因为大多数时候,用户仅仅知道某个博客的首页地址,并不知道XMLFeed的具体地址,而且,某些Feed地址很长,不便于用户输入。FeedFetcher还需要从一个HTML中分析并提取出Feed地址,其discoverypublicString[]discover(Stringurl){...URL本身就是一个XMLFeed时,FeedFetcherURL是一个HTML时,FeedFetcher就需要解析HTML。由于HTML格式并非严格遵循XML规范,所以,无法使用XML解析器如DOM和SAX解析。开源项目HTMLParser()提供了将HTML解析为DOM树的功能,同时,它还能处理不太规范的HTML,例如,<BR>之类没有结束的标签。但是,正如前面我们提到的,解析一个DOMJava应用,完全可因此,RSSReader不采用HTMLParser解析HTML,而是直接将HTML看作一个字符串,通过搜索字符串“<link”来实现,既简单又高效。代码如下:Stringhtml=loadHtml(url);intstart=0;List<String>list=newArrayList<String>(5);for(;;){intpos=html.indexOf("<link",start);if(pos==(-1))break;intend=html.indexOf(">",pos);if(end==(-1))break;Stringlink=extractFeedUrl(html.substring(pos,end+1),url);if(link!=null)list.add(link);start=end+1;}当我们发现匹配到“<link...>”时,就通过extractFeedUrl()方法解析该<link>,根据其rel、和href属性确认是否是一个有效的StringextractFeedUrl(Stringlink,StringbaseUrl){if(link.indexOf("rel='alternate'")==(-1)&&link.indexOf("rel=\"alternate\"")==(-1))returnnull;if(link.indexOf("type='application/rss+xml'")==(-1)&&link.indexOf("type=\"application/rss+xml\"")==(-1)&&link.indexOf("type='application/atom+xml'")==(-1)&&link.indexOf("type=\"application/atom+xml\"")==(-1))returnnull;intpos=link.indexOf("href='");if(pos==(-1))pos=link.indexOf("href=\"");if(pos==(-1))returnnull;intend=link.indexOf('\'',pos+6);if(end==(-1))end=link.indexOf('\"',pos+6);if(end==(-1))returnnull;Stringhref=link.substring(pos+6,end);if(href.startsWith("http://")||href.startsWith("https://"))returnhref;returngetAbsoluteUrl(baseUrl,href);}这里要特殊处理的是,如果href一旦我们编写了Feed的发现功能和解析功能后,就可以在SubsActivity中实现对订阅的管理功能了。我们先编写添加Feed的功能。仿照MainActivity的选项菜单,我们添加一个“Add”菜单项,并响应菜单,给用户显示一个AlertDialog,提示用户输入Feed地址:privatevoidaddSubscription(){finalAlertDialog.Builderalert=newAlertDialog.Builder(this);alert.setTitle("AddSubscription");alert.setMessage("AddsubscriptionfromURL:");EditText以便用户输入:finalEditTextinput=newEditText(this);input.setSingleLine();input.setText("http://");alert.setView(input);alert.setPositiveButton(android.R.string.ok,newDialogInterface.OnClickListener(){publicvoidonClick(DialogInterfacedialog,intwhichButton){discover(input.getText().toString());}});alert.setNegativeButton(android.R.string.cancel,newDialogInterface.OnClickListener(){publicvoidonClick(DialogInterfacedialog,intwhichButton){}});alert.show();}AlertDialog使用标准的Builder模式,我们需要初始化一个AlertDialog.Builder的实例,设置标题和描述。AlertDialog还可以接受一个View,我们实例化一个EditTextsetView()AlertDialog,URLsetPositiveButton()setNegativeButton()AlertDialog设置一个“OK”和一个“Cancel”按钮,并分别响应Click。最后,调用show()方法显示AlertDialog,运行效果如当用户输入了有效的URL地址,并点击“OK”按钮后,SubsActivity就需要该URL以确定是否是一个有效的FeedURL中发现Feed。由于这是一个联网操作,不能直接放在主线行,因此,我们仍然使用前面讲到的Asynk,异步获取Feed地址:privateProgressDialogprogress=null;voiddiscover(String{Stringurl=formatURL(value);gress=ProgressDialog.show(this,"Loading","Loadingfeeds...",true);Asynk<String,ProgressDialog,String[]>asynk=newAsynk<String,ProgressDialog,String[]>(){@OverrideprotectedString[]nBackground(String...params){finalFeedFetcherfetchernewFeedFetcher();returnfetcher.discover(params[0]);@OverrideprotectedvoidonPostExecute(String[]result)Loading框:if(SubsAgress!=null)SubsAgress.dismiss();SubsAgressnull;}//处理发现的Feed:addFeeds(result);}};asynk.execute(url);}这里我们需要构造一个ProgressDialogAlertDialog还要简单,通过ProgressDialog.show()就可以显示一个ProgressDialog,然后,启动Asynk,当Asynk任务完成后,我们需要调用ProgressDialog.dismiss()ProgressDialog。以上代码运行效果如下:现在,我们已经实现了从URL发现Feed,通过Asynk从网络获得XML内容,并在中显示每个Item项。当用户需要查看某一Item时,我们如何为用户显示Item使用当用户点击MainActivity的某一列表项时,我们需要启动ReadActivity来显示Item的详细内容。由于从RSS抓取的Item内容都是HTML格式,因此,要显示ItemWebView是最简单最快WebView可以显示Web页面,并且,可以像普通的View那样应用到任何布局中。实际上,WebView和OPhone系统的浏览器使用的是完全一样的内核,只要我们愿意,完全可以通过WebView开发我们自己的浏览器,功能可以做到和OPhone的系统浏览器一样,这和Windows应用程序中可以嵌入IE是一我们首先为ReadActivity定义布局read.xml<?xmlversion="1.0"encoding="utf-8"?><LinearLayout android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:paddingLeft="6dip"android:paddingRight="6dip"><WebViewandroid:id="@+android:id/webview"android:layout_width="fill_parent"android:background="@android:color/black"/></LinearLayout>WebView默认的背景色是白色,为了与应用程序的背景色一致,在“android:background”属性中指定WebView提供了两个方法用于显示网页的内容:loadUrl()URLloadData()则用于直接向WebView写入指定的HTML文本。此外,loadDataWithBaseURL()loadData()类似,但是,如果写入的HTML文本包含、CSS等外部资源的相对时,WebView就会根据指定的baseURL来正确地加载这些资源,这个方法正好符合我们显示Item的需求,编写代码如下:@OverrideprotectedvoidonCreate(Bundle{super.onCreate(savedInstanceState);setContentView(R.layout.read);Itemitem=loadItem(...);//TODO:loaditemfromdatabaseStringurl=item.url;Stringtitle=item.title;Stringcon
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 17980.50-2026农药田间药效试验准则第50部分:除草剂防治甜菜田杂草
- 2026国航股份贵州分公司招收12人笔试备考题库及答案解析
- 中国人民解放军第五七一八工厂 2026届校园招聘笔试模拟试题及答案解析
- 2026广西百色市田阳区产业投资集团有限公司就业见习生招聘2人笔试备考题库及答案解析
- 2026中交雄安投资有限公司招聘笔试参考题库及答案解析
- 2026年3月广东广州市天河区龙口中路幼儿园编外人员招聘1人笔试备考试题及答案解析
- 2026年福建福州市教育局福州市直中小学幼儿园教师补充招聘37人笔试参考题库及答案解析
- 甘肃省平凉市静宁县重点名校2026年初三4月期中练习(二模)英语试题(理、文合卷)试题含解析
- 湖南省益阳市安化县2026届初三一诊考试-英语试题含解析
- 2026届辽宁省抚顺县初三英语试题下学期期末教学质量检测试题含解析
- 女装成衣设计与工艺技术
- 初中英语一般过去时专项练习
- 《数字图像与视频处理》第9章 图像与视频的质量评价PPT
- 面瘫诊疗方案优化方案
- 中国图书馆分类法简表
- 新课程的教育理念 义务教育物理课程标准解读 新课标
- 地质灾害防治工程课件
- 糖尿病慢性并发症P课件
- 经皮肾镜碎石术并发脓毒血症的风险与防治
- 消防燃烧学课件
- 军用工程机械简介课件
评论
0/150
提交评论