Android RSS阅读器应用程序

时间:2020-02-23 14:29:14  来源:igfitidea点击:

在本教程中,我们将讨论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权限。