RSS Feed无法填充TextView问题排查求助
BBC RSS Feed 无法填充TextView的问题排查
问题描述
我正在开发一个新闻阅读器项目,需将BBC的RSS Feed加载到TextView中。代码逻辑看似无误,但TextView始终无法填充内容,调试后怀疑是未正确实现open stream导致的。相关代码如下:
package com.example.finalproject_newsapp; import androidx.appcompat.app.AppCompatActivity; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import android.os.Bundle; import android.widget.ListView; import android.widget.TextView; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; public class MainActivity extends AppCompatActivity { String rss = ""; boolean item = false; private class RSSHandler extends DefaultHandler { public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { if (localName.equals("item")) item = true; if (!localName.equals("item") && item == true) rss = rss + localName + ": "; } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { } public void characters(char[] ch, int start, int length) throws SAXException { String cdata = new String(ch, start, length); if (item == true) rss = rss + (cdata.trim()).replaceAll("\\s+", " ") + " "; } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView feed = findViewById(R.id.BBC_feed); try { URL rssUrl = new URL("http://feeds.bbci.co.uk/news/world/us_and_canada/rss.xml"); SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser saxParser = factory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); RSSHandler rssHandler = new RSSHandler(); xmlReader.setContentHandler(rssHandler); InputSource inputSource = new InputSource(rssUrl.openStream()); xmlReader.parse(inputSource); } catch (MalformedURLException | ParserConfigurationException | SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } feed.setText(rss); } }
问题原因排查
- 主线程网络操作被拦截:Android从API 9开始禁止在主线程(如
onCreate方法)执行网络请求,代码里的rssUrl.openStream()会触发NetworkOnMainThreadException,但当前异常捕获未覆盖该异常(或堆栈打印被忽略),导致RSS解析完全没执行,rss字符串始终为空。 - SAX解析未处理命名空间:BBC的RSS Feed带有命名空间,默认SAX配置未开启命名空间支持,导致
localName无法获取正确标签名(实际标签带命名空间前缀),localName.equals("item")判断永远不成立,item变量一直为false,不会往rss里拼接内容。 - 缺少item结束标签处理:
endElement方法无逻辑,解析完item标签后item变量不会重置为false,后续非item标签可能被错误拼接,但这不是空内容的主要原因。 - 无网络权限:如果
AndroidManifest.xml未添加<uses-permission android:name="android.permission.INTERNET"/>,网络请求直接失败,rss自然为空。
修复建议
- 将网络操作移到子线程:把RSS解析逻辑放到子线程执行,完成后回到主线程更新TextView,示例代码:
new Thread(new Runnable() { @Override public void run() { try { URL rssUrl = new URL("http://feeds.bbci.co.uk/news/world/us_and_canada/rss.xml"); SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); // 开启命名空间支持 SAXParser saxParser = factory.newSAXParser(); XMLReader xmlReader = saxParser.getXMLReader(); RSSHandler rssHandler = new RSSHandler(); xmlReader.setContentHandler(rssHandler); InputSource inputSource = new InputSource(rssUrl.openStream()); xmlReader.parse(inputSource); // 回到主线程更新UI runOnUiThread(new Runnable() { @Override public void run() { feed.setText(rss); } }); } catch (Exception e) { e.printStackTrace(); runOnUiThread(() -> feed.setText("加载失败:" + e.getMessage())); } } }).start(); - 开启SAX命名空间支持:创建
SAXParserFactory后调用factory.setNamespaceAware(true);,确保localName能正确获取不带命名空间的标签名。 - 完善endElement逻辑:在
endElement方法中添加代码,遇到item结束标签时重置item为false,并给每个item添加换行分隔:@Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { if (localName.equals("item")) { item = false; rss += "\n\n"; } } - 添加网络权限:在
AndroidManifest.xml中添加网络权限声明:<uses-permission android:name="android.permission.INTERNET"/>
内容的提问来源于stack exchange,提问作者ReginaldRey
相关产品推荐
相关产品推荐

