Android RSS阅读器应用程序
在本教程中,我们将讨论Android RSS Reader并在android studio中开发RSS Feed Reader应用。
Android RSS Feed Reader应用程序将展示来自两个热门的电影注释。
Android RSS阅读器
RSS代表Really Simple Syndication。
通常会为其内容提供RSS Feed。
它采用XML格式,通常用于访问中提供的最新内容。
RSS Feed xml文档如下所示:
<channel> <title></title> <link></link> <description></description> <item> <title></title> <link></link> <pubDate></pubDate> <description></description> </item> <item> . . . . </item> </channel>
channel是用于容纳以下元素的根元素。
title是的标题。
链接包含项目元素的网址,该网址由内容组成。
每个项目都描述相应内容的标题,URL,发布日期和描述(正文)。
在下面的Android项目中,我们将使用DocumentBuilderFactory实例来解析xml文档。
我们将使用HttpClient和jsoup jar库在AsyncTask中获取的XML feed内容。
我们将开发一个应用程序,使用其RSS Feed从两个(Rediff.com和Cinemablend.com)获取电影注释,并以ListView的形式显示项目。
单击任何ListView将在WebView中打开其内容。
让我们开始吧。
Android RSS Feed阅读器项目结构
该项目包括三个活动。
第一个包含两个按钮,它们将充当两个的RSS源的链接。
第二个将以ListView的形式显示包含电影注释的最新RSS Feed。
第三个将打开上一个活动中选择的任何"列表行"中的链接,并将URL加载到WebView中。
我们已经将jsoup.jar导入了我们的libs文件夹中。
我们需要在build.gradle的android {}块中设置" useLibrary'org.apache.http.legacy'",如下所示:
这样做是为了允许在我们的活动中导入HtttpClient和HttpUrlConnection类。
Android RSS阅读器代码
下面给出了activity_main.xml布局类的代码:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <Button android:id="@+id/btnRediff" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="REDIFF.COM RSS FEED" <Button android:id="@+id/btnCinemaBlend" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="CINEMA BLEND RSS FEED" </LinearLayout>
MainActivity.java类的代码如下:
package com.theitroad.androidrssfeedtutorial; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import java.util.ArrayList; public class MainActivity extends AppCompatActivity implements View.OnClickListener { ArrayList<String> rssLinks = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button btnRediff = findViewById(R.id.btnRediff); Button btnCinemaBlend = findViewById(R.id.btnCinemaBlend); btnRediff.setOnClickListener(this); btnCinemaBlend.setOnClickListener(this); rssLinks.add("https://www.rediff.com/rss/moviesreviewsrss.xml"); rssLinks.add("https://www.cinemablend.com/rss_review.php"); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btnRediff: startActivity(new Intent(MainActivity.this, RSSFeedActivity.class).putExtra("rssLink", rssLinks.get(0))); break; case R.id.btnCinemaBlend: startActivity(new Intent(MainActivity.this, RSSFeedActivity.class).putExtra("rssLink", rssLinks.get(1))); break; } } }
在此,我们通过Intents将RSS Url链接传递到我们接下来将看到的RSSFeedActivity.java类。
下面给出了activity_rss_feed.xml布局的代码:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/relativeLayout" android:orientation="vertical"> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" android:dividerHeight="1dp" </RelativeLayout>
下面给出了扩展ListActivity的RSSFeedActivity.java类的代码。
package com.theitroad.androidrssfeedtutorial; import android.app.ListActivity; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.SimpleAdapter; import android.widget.TextView; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; public class RSSFeedActivity extends ListActivity { private ProgressBar pDialog; ArrayList<HashMap<String, String>> rssItemList = new ArrayList<>(); RSSParser rssParser = new RSSParser(); Toolbar toolbar; List<RSSItem> rssItems = new ArrayList<>(); private static String TAG_TITLE = "title"; private static String TAG_LINK = "link"; private static String TAG_PUB_DATE = "pubDate"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_rss_feed); String rss_link = getIntent().getStringExtra("rssLink"); new LoadRSSFeedItems().execute(rss_link); ListView lv = getListView(); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { public void onItemClick(AdapterView<?> parent, View view, int position, long id) { Intent in = new Intent(getApplicationContext(), BrowserActivity.class); String page_url = ((TextView) view.findViewById(R.id.page_url)).getText().toString().trim(); in.putExtra("url", page_url); startActivity(in); } }); } public class LoadRSSFeedItems extends AsyncTask<String, String, String> { @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressBar(RSSFeedActivity.this, null, android.R.attr.progressBarStyleLarge); RelativeLayout relativeLayout = findViewById(R.id.relativeLayout); RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams( RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT ); lp.addRule(RelativeLayout.CENTER_IN_PARENT); pDialog.setLayoutParams(lp); pDialog.setVisibility(View.VISIBLE); relativeLayout.addView(pDialog); } @Override protected String doInBackground(String... args) { //rss link url String rss_url = args[0]; //list of rss items rssItems = rssParser.getRSSFeedItems(rss_url); //looping through each item for (RSSItem item : rssItems) { //creating new HashMap if (item.link.toString().equals("")) break; HashMap<String, String> map = new HashMap<String, String>(); //adding each child node to HashMap key => value String givenDateString = item.pubdate.trim(); SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z"); try { Date mDate = sdf.parse(givenDateString); SimpleDateFormat sdf2 = new SimpleDateFormat("EEEE, dd MMMM yyyy - hh:mm a", Locale.US); item.pubdate = sdf2.format(mDate); } catch (ParseException e) { e.printStackTrace(); } map.put(TAG_TITLE, item.title); map.put(TAG_LINK, item.link); map.put(TAG_PUB_DATE, item.pubdate); //If you want parse the date //adding HashList to ArrayList rssItemList.add(map); } //updating UI from Background Thread runOnUiThread(new Runnable() { public void run() { ListAdapter adapter = new SimpleAdapter( RSSFeedActivity.this, rssItemList, R.layout.rss_item_list_row, new String[]{TAG_LINK, TAG_TITLE, TAG_PUB_DATE}, new int[]{R.id.page_url, R.id.title, R.id.pub_date}); //updating listview setListAdapter(adapter); } }); return null; } protected void onPostExecute(String args) { pDialog.setVisibility(View.GONE); } } }
在此,我们实例化RSSParser类的实例。
在LoadRSSFeedItems AsyncTask方法内部,我们调用getRSSFeedItems()
以从URL获取RSSItem,然后将其存储在rssItems的ArrayList中。
然后将RSSItems ArrayList最终加载到ListView行中。
rss_item_list_row.xml布局的代码如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="8dip"> <TextView android:id="@+id/page_url" android:layout_width="fill_parent" android:layout_height="wrap_content" android:visibility="gone" <TextView android:id="@+id/title" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingBottom="1dip" android:textColor="#212121" android:textSize="18sp" android:textStyle="bold" <TextView android:id="@+id/pub_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/title" android:paddingBottom="3dip" android:textColor="#9b737775" android:textSize="14sp" </RelativeLayout>
在ListView行的单击侦听器上,我们将当前项目的url传递给键" url"中的下一个Activity。
在查看下一个活动之前,让我们看一下RSSItem.java和RSSParser.java类。
不要忘记在列表文件中添加活动。
RSSItem.java
package com.theitroad.androidrssfeedtutorial; / public class RSSItem { public String title; public String link; public String description; public String pubdate; public String guid; public RSSItem(String title, String link, String description, String pubdate, String guid) { this.title = title; this.link = link; this.description = description; this.pubdate = pubdate; this.guid = guid; } }
RSSParser.java
这负责解析xml feed文档。
package com.theitroad.androidrssfeedtutorial; import android.util.Log; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; public class RSSParser { //RSS XML document CHANNEL tag private static String TAG_CHANNEL = "channel"; private static String TAG_TITLE = "title"; private static String TAG_LINK = "link"; private static String TAG_DESRIPTION = "description"; private static String TAG_ITEM = "item"; private static String TAG_PUB_DATE = "pubDate"; private static String TAG_GUID = "guid"; //constructor public RSSParser() { } public List<RSSItem> getRSSFeedItems(String rss_url) { List<RSSItem> itemsList = new ArrayList<RSSItem>(); String rss_feed_xml; rss_feed_xml = this.getXmlFromUrl(rss_url); if (rss_feed_xml != null) { try { Document doc = this.getDomElement(rss_feed_xml); NodeList nodeList = doc.getElementsByTagName(TAG_CHANNEL); Element e = (Element) nodeList.item(0); NodeList items = e.getElementsByTagName(TAG_ITEM); for (int i = 0; i < items.getLength(); i++) { Element e1 = (Element) items.item(i); String title = this.getValue(e1, TAG_TITLE); String link = this.getValue(e1, TAG_LINK); String description = this.getValue(e1, TAG_DESRIPTION); String pubdate = this.getValue(e1, TAG_PUB_DATE); String guid = this.getValue(e1, TAG_GUID); RSSItem rssItem = new RSSItem(title, link, description, pubdate, guid); //adding item to list itemsList.add(rssItem); } } catch (Exception e) { //Check log for errors e.printStackTrace(); } } //return item list return itemsList; } public String getXmlFromUrl(String url) { String xml = null; try { DefaultHttpClient httpClient = new DefaultHttpClient(); HttpGet httpGet = new HttpGet(url); HttpResponse httpResponse = httpClient.execute(httpGet); HttpEntity httpEntity = httpResponse.getEntity(); xml = EntityUtils.toString(httpEntity); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } //return XML return xml; } public Document getDomElement(String xml) { Document doc = null; DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { DocumentBuilder db = dbf.newDocumentBuilder(); InputSource is = new InputSource(); is.setCharacterStream(new StringReader(xml)); doc = db.parse(is); } catch (ParserConfigurationException e) { Log.e("Error: ", e.getMessage()); return null; } catch (SAXException e) { Log.e("Error: ", e.getMessage()); return null; } catch (IOException e) { Log.e("Error: ", e.getMessage()); return null; } return doc; } public final String getElementValue(Node elem) { Node child; if (elem != null) { if (elem.hasChildNodes()) { for (child = elem.getFirstChild(); child != null; child = child .getNextSibling()) { if (child.getNodeType() == Node.TEXT_NODE || (child.getNodeType() == Node.CDATA_SECTION_NODE)) { return child.getNodeValue(); } } } } return ""; } public String getValue(Element item, String str) { NodeList n = item.getElementsByTagName(str); return this.getElementValue(n.item(0)); } }
getRSSFeedItems()是将RSSItem列表返回到RSSFeedActivity.java的功能。
下面给出了activity_browser.xml布局的代码。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:id="@+id/relativeLayout" android:layout_height="match_parent"> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <WebView android:id="@+id/webView" android:layout_width="match_parent" android:layout_height="match_parent" </android.support.v4.widget.NestedScrollView> </RelativeLayout>
下面给出了BrowserActivity.java类的代码。
package com.theitroad.androidrssfeedtutorial; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.webkit.WebChromeClient; import android.webkit.WebResourceError; import android.webkit.WebResourceRequest; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; public class BrowserActivity extends AppCompatActivity { WebView webView; String url; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_browser); Intent in = getIntent(); url = in.getStringExtra("url"); if (TextUtils.isEmpty(url)) { Toast.makeText(getApplicationContext(), "URL not found", Toast.LENGTH_SHORT).show(); finish(); } webView = findViewById(R.id.webView); initWebView(); webView.loadUrl(url); } private void initWebView() { webView.setWebChromeClient(new MyWebChromeClient(this)); webView.clearCache(true); webView.getSettings().setJavaScriptEnabled(true); webView.setHorizontalScrollBarEnabled(false); webView.setWebViewClient(new WebViewClient() { @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { webView.loadUrl(url); return true; } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); } @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { super.onReceivedError(view, request, error); invalidateOptionsMenu(); } }); webView.clearCache(true); webView.clearHistory(); webView.getSettings().setJavaScriptEnabled(true); webView.setHorizontalScrollBarEnabled(false); } private class MyWebChromeClient extends WebChromeClient { Context context; public MyWebChromeClient(Context context) { super(); this.context = context; } } }
从RSSFeedActivity.java Activity传递的url被加载到这里。
不要忘记在您的AndroidManifest.xml文件中添加Internet权限。