Android RSS阅读器教程

In this android rss reader tutorial we will see how to make demo app that can read rss of a website or blog. So without wasting much time lets begin.

在这个android rss阅读器教程中,我们将了解如何制作可读取网站或博客rss的演示应用程序。 因此,在不浪费大量时间的情况下开始吧。

Typically the rss feed of a website or blog look something like shown below.

通常,网站或博客的rss feed如下所示。

<channel>
    <title></title>
    <link></link>
    <description></description>
 
    <item>
        <title></title>
        <link></link>
        <pubDate></pubDate>
        <description></description>
    </item>
 
    <item>
        <title></title>
        <link></link>
        <pubDate></pubDate>
        <description></description>
    </item>
 
	.
	.
	.
	.
 
</channel>

The data we get is in xml format.

我们获得的数据为xml格式。

Here channel tag is the root or the main element from where rss begins.

这里的channel标签是rss的根或主要元素。

title shows the name of the website.

标题显示网站的名称。

description tells the content of website.

描述说明了网站的内容。

link is the url to the website.

链接是网站的网址。

There are multiple item tags that contain article or post information like post title, link, publish date, etc.

有多个项目标签,其中包含文章或文章信息,例如文章标题,链接,发布日期等。

First of all create a new android project to read the rss in android app.

首先创建一个新的android项目,以读取android应用程序中的rss。

Then we need to give internet permission in manifest to access the rss in application.

然后,我们需要在清单中授予Internet权限以访问应用程序中的rss。

<uses-permission android:name="android.permission.INTERNET"/>

Now we are adding some of the dependency that we need in our project.

现在,我们在项目中添加了一些需要的依赖。

implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:recyclerview-v7:28.0.0'
implementation 'com.android.support:cardview-v7:28.0.0'

We are designing our activity_main.xml file.

我们正在设计activity_main.xml文件。

activity_main.xml

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
      tools:context=".MainActivity">
 
    <Button
        android:id="@+id/fetchFeedButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:text="Fetch" />
 
    <android.support.design.widget.TextInputLayout
        android:id="@+id/textInputLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginEnd="10dp"
        android:layout_toStartOf="@id/fetchFeedButton"
        android:hint="Rss feed source">
 
        <EditText
            android:id="@+id/rssFeedEditText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
 
    </android.support.design.widget.TextInputLayout>
 
    <TextView
        android:id="@+id/feedTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/textInputLayout"
        android:text="Feed Title: " />
 
    <TextView
        android:id="@+id/feedDescription"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/feedTitle"
        android:text="Feed Description: " />
 
    <android.support.v4.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/feedDescription"
        android:layout_marginTop="20dp">
 
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>

Here we are using swipe refresh layout just to refresh the rss content of a website.

在这里,我们使用滑动刷新布局只是为了刷新网站的rss内容。

Now we have to code MainActivity.java for building our functionality of application so first we have to reference xml components in java.

现在我们必须编码MainActivity.java来构建应用程序的功能,因此首先我们必须引用java中的xml组件。

public class MainActivity extends AppCompatActivity {
 
    private RecyclerView mRecyclerView;
    private EditText mEditText;
    private Button mFetchFeedButton;
    private SwipeRefreshLayout mSwipeLayout;
    private TextView mFeedTitleTextView;
    private TextView mFeedDescriptionTextView;
 
    private List<RssFeedModel> mFeedModelList;
    private String mFeedTitle;
    private String mFeedContent;
    private String mFeedDescription;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        mEditText = (EditText) findViewById(R.id.rssFeedEditText);
        mFetchFeedButton = (Button) findViewById(R.id.fetchFeedButton);
        mSwipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
        mFeedTitleTextView = (TextView) findViewById(R.id.feedTitle);
        mFeedDescriptionTextView = (TextView) findViewById(R.id.feedDescription);
 
 
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
 
        mFetchFeedButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new FetchFeedTask().execute((Void) null);
            }
        });
        mSwipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new FetchFeedTask().execute((Void) null);
            }
        });
    }

We have to define a java class called FetchFeedTask which is used to get the rss feed from url.

我们必须定义一个名为FetchFeedTask的Java类,该类用于从url获取rss feed。

private class FetchFeedTask extends AsyncTask<Void, Void, Boolean> {
 
    private String urlLink;
 
    @Override
    protected void onPreExecute() {
        mSwipeLayout.setRefreshing(true);
        urlLink = mEditText.getText().toString();
    }
 
    @Override
    protected Boolean doInBackground(Void... voids) {
        if (TextUtils.isEmpty(urlLink))
            return false;
 
        try {
            if(!urlLink.startsWith("http://") && !urlLink.startsWith("https://"))
                urlLink = "http://" + urlLink;
 
            URL url = new URL(urlLink);
            InputStream inputStream = url.openConnection().getInputStream();
            mFeedModelList = parseFeed(inputStream);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
        return false;
    }
 
    @Override
    protected void onPostExecute(Boolean success) {
        mSwipeLayout.setRefreshing(false);
 
        if (success) {
            mFeedTitleTextView.setText("Feed Title: " + mFeedTitle);
            mFeedDescriptionTextView.setText("Feed Description: " + mFeedDescription);
            // Fill RecyclerView
            mRecyclerView.setAdapter(new RssFeedListAdapter(mFeedModelList));
 
        } else {
            Toast.makeText(MainActivity.this,
                    "Enter a valid Rss feed url",
                    Toast.LENGTH_LONG).show();
        }
    }
}

Now we are defining a list and parsing xml data to get the attribute of items from the rss feed we have extracted.

现在,我们定义一个列表并解析xml数据,以从已提取的rss feed中获取项目的属性。

public List<RssFeedModel> parseFeed(InputStream inputStream) throws XmlPullParserException,
        IOException {
    String title = null;
    String content = null;
    String description = null;
    boolean isItem = false;
    List<RssFeedModel> items = new ArrayList<>();
 
    try {
        XmlPullParser xmlPullParser = Xml.newPullParser();
        xmlPullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
        xmlPullParser.setInput(inputStream, null);
 
        xmlPullParser.nextTag();
        while (xmlPullParser.next() != XmlPullParser.END_DOCUMENT) {
            int eventType = xmlPullParser.getEventType();
 
            String name = xmlPullParser.getName();
            if(name == null)
                continue;
 
            if(eventType == XmlPullParser.END_TAG) {
                if(name.equalsIgnoreCase("item")) {
                    isItem = false;
                }
                continue;
            }
 
            if (eventType == XmlPullParser.START_TAG) {
                if(name.equalsIgnoreCase("item")) {
                    isItem = true;
                    continue;
                }
            }
 
            Log.d("MyXmlParser", "Parsing name ==> " + name);
            String result = "";
            if (xmlPullParser.next() == XmlPullParser.TEXT) {
                result = xmlPullParser.getText();
                xmlPullParser.nextTag();
            }
 
            if (name.equalsIgnoreCase("title")) {
                title = result;
            } else if (name.equalsIgnoreCase("content:encoded")) {
                content = result;
            } else if (name.equalsIgnoreCase("description")) {
                description = result;
            }
 
            if (title != null && content != null && description != null) {
                if(isItem) {
                    RssFeedModel item = new RssFeedModel(title, content, description);
                    items.add(item);
                }
                else {
                    mFeedTitle = title;
                    mFeedContent = content;
                    mFeedDescription = description;
                }
 
                title = null;
                content = null;
                description = null;
                isItem = false;
            }
        }
 
        return items;
    } finally {
        inputStream.close();
    }
}

Defining RssModel java class which we used to hold the attribute of every post.

定义我们用来保存每个帖子属性的RssModel java类。

public class RssFeedModel {
 
        public String title;
        public String content;
        public String description;
 
        public RssFeedModel(String title, String content, String description) {
            this.title = title;
            this.content = content;
            this.description = description;
        }
    }

Defining RecyclerAdapter to attach our list data to recyclerview.

定义RecyclerAdapter以将我们的列表数据附加到recyclerview。

public class RssFeedListAdapter
            extends RecyclerView.Adapter<RssFeedListAdapter.FeedModelViewHolder> {
 
        private List<RssFeedModel> mRssFeedModels;
 
        public  class FeedModelViewHolder extends RecyclerView.ViewHolder {
            private View rssFeedView;
 
            public FeedModelViewHolder(View v) {
                super(v);
                rssFeedView = v;
            }
        }
 
        public RssFeedListAdapter(List<RssFeedModel> rssFeedModels) {
            mRssFeedModels = rssFeedModels;
        }
 
        @Override
        public FeedModelViewHolder onCreateViewHolder(ViewGroup parent, int type) {
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recycler_layout, parent, false);
            FeedModelViewHolder holder = new FeedModelViewHolder(v);
            return holder;
        }
 
        @Override
        public void onBindViewHolder(FeedModelViewHolder holder, int position) {
            final RssFeedModel rssFeedModel = mRssFeedModels.get(position);
            ((TextView)holder.rssFeedView.findViewById(R.id.titleText)).setText(rssFeedModel.title);
 
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                ((TextView)holder.rssFeedView.findViewById(R.id.descriptionText)).setText(Html.fromHtml(rssFeedModel.description,Html.FROM_HTML_MODE_LEGACY));
            } else {
                ((TextView)holder.rssFeedView.findViewById(R.id.descriptionText)).setText(Html.fromHtml(rssFeedModel.description));	//we have used Html.fromHtml() in textview to make our textView support html content
            }
 
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
 
                    Intent intent=new Intent(getApplicationContext(),Final.class);
                    intent.putExtra("content",rssFeedModel.content);
                    startActivity(intent);
 
                }
            });
 
 
               }
 
 
        @Override
        public int getItemCount() {
            return mRssFeedModels.size();
        }
    }

Finally the MainActivity.java file will look like.

最终,MainActivity.java文件将如下所示。

MainActivity.java

MainActivity.java

package com.example.anmol.rssdemo;
 
import android.content.Intent;
import android.os.AsyncTask;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
 
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
 
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class MainActivity extends AppCompatActivity {
 
    private RecyclerView mRecyclerView;
    private EditText mEditText;
    private Button mFetchFeedButton;
    private SwipeRefreshLayout mSwipeLayout;
    private TextView mFeedTitleTextView;
    private TextView mFeedDescriptionTextView;
 
    private List<RssFeedModel> mFeedModelList;
    private String mFeedTitle;
    private String mFeedContent;
    private String mFeedDescription;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        mEditText = (EditText) findViewById(R.id.rssFeedEditText);
        mFetchFeedButton = (Button) findViewById(R.id.fetchFeedButton);
        mSwipeLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
        mFeedTitleTextView = (TextView) findViewById(R.id.feedTitle);
        mFeedDescriptionTextView = (TextView) findViewById(R.id.feedDescription);
 
 
        mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
 
        mFetchFeedButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                new FetchFeedTask().execute((Void) null);
            }
        });
        mSwipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {
                new FetchFeedTask().execute((Void) null);
            }
        });
    }
    private class FetchFeedTask extends AsyncTask<Void, Void, Boolean> {
 
        private String urlLink;
 
        @Override
        protected void onPreExecute() {
            mSwipeLayout.setRefreshing(true);
            urlLink = mEditText.getText().toString();
        }
 
        @Override
        protected Boolean doInBackground(Void... voids) {
            if (TextUtils.isEmpty(urlLink))
                return false;
 
            try {
                if(!urlLink.startsWith("http://") && !urlLink.startsWith("https://"))
                    urlLink = "http://" + urlLink;
 
                URL url = new URL(urlLink);
                InputStream inputStream = url.openConnection().getInputStream();
                mFeedModelList = parseFeed(inputStream);
                return true;
            } catch (IOException e) {
                e.printStackTrace();
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            }
            return false;
        }
 
        @Override
        protected void onPostExecute(Boolean success) {
            mSwipeLayout.setRefreshing(false);
 
            if (success) {
                mFeedTitleTextView.setText("Feed Title: " + mFeedTitle);
                mFeedDescriptionTextView.setText("Feed Description: " + mFeedDescription);
                // Fill RecyclerView
                mRecyclerView.setAdapter(new RssFeedListAdapter(mFeedModelList));
 
            } else {
                Toast.makeText(MainActivity.this,
                        "Enter a valid Rss feed url",
                        Toast.LENGTH_LONG).show();
            }
        }
    }
 
    public List<RssFeedModel> parseFeed(InputStream inputStream) throws XmlPullParserException,
            IOException {
        String title = null;
        String content = null;
        String description = null;
        boolean isItem = false;
        List<RssFeedModel> items = new ArrayList<>();
 
        try {
            XmlPullParser xmlPullParser = Xml.newPullParser();
            xmlPullParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
            xmlPullParser.setInput(inputStream, null);
 
            xmlPullParser.nextTag();
            while (xmlPullParser.next() != XmlPullParser.END_DOCUMENT) {
                int eventType = xmlPullParser.getEventType();
 
                String name = xmlPullParser.getName();
                if(name == null)
                    continue;
 
                if(eventType == XmlPullParser.END_TAG) {
                    if(name.equalsIgnoreCase("item")) {
                        isItem = false;
                    }
                    continue;
                }
 
                if (eventType == XmlPullParser.START_TAG) {
                    if(name.equalsIgnoreCase("item")) {
                        isItem = true;
                        continue;
                    }
                }
 
                Log.d("MyXmlParser", "Parsing name ==> " + name);
                String result = "";
                if (xmlPullParser.next() == XmlPullParser.TEXT) {
                    result = xmlPullParser.getText();
                    xmlPullParser.nextTag();
                }
 
                if (name.equalsIgnoreCase("title")) {
                    title = result;
                } else if (name.equalsIgnoreCase("content:encoded")) {
                    content = result;
                } else if (name.equalsIgnoreCase("description")) {
                    description = result;
                }
 
                if (title != null && content != null && description != null) {
                    if(isItem) {
                        RssFeedModel item = new RssFeedModel(title, content, description);
                        items.add(item);
                    }
                    else {
                        mFeedTitle = title;
                        mFeedContent = content;
                        mFeedDescription = description;
                    }
 
                    title = null;
                    content = null;
                    description = null;
                    isItem = false;
                }
            }
 
            return items;
        } finally {
            inputStream.close();
        }
    }
    public class RssFeedModel {
 
        public String title;
        public String content;
        public String description;
 
        public RssFeedModel(String title, String content, String description) {
            this.title = title;
            this.content = content;
            this.description = description;
        }
    }
 
    public class RssFeedListAdapter
            extends RecyclerView.Adapter<RssFeedListAdapter.FeedModelViewHolder> {
 
        private List<RssFeedModel> mRssFeedModels;
 
        public  class FeedModelViewHolder extends RecyclerView.ViewHolder {
            private View rssFeedView;
 
            public FeedModelViewHolder(View v) {
                super(v);
                rssFeedView = v;
            }
        }
 
        public RssFeedListAdapter(List<RssFeedModel> rssFeedModels) {
            mRssFeedModels = rssFeedModels;
        }
 
        @Override
        public FeedModelViewHolder onCreateViewHolder(ViewGroup parent, int type) {
            View v = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.recycler_layout, parent, false);
            FeedModelViewHolder holder = new FeedModelViewHolder(v);
            return holder;
        }
 
        @Override
        public void onBindViewHolder(FeedModelViewHolder holder, int position) {
            final RssFeedModel rssFeedModel = mRssFeedModels.get(position);
            ((TextView)holder.rssFeedView.findViewById(R.id.titleText)).setText(rssFeedModel.title);
 
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
                ((TextView)holder.rssFeedView.findViewById(R.id.descriptionText)).setText(Html.fromHtml(rssFeedModel.description,Html.FROM_HTML_MODE_LEGACY));
            } else {
                ((TextView)holder.rssFeedView.findViewById(R.id.descriptionText)).setText(Html.fromHtml(rssFeedModel.description));
            }
 
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
 
                    Intent intent=new Intent(getApplicationContext(),Final.class);
                    intent.putExtra("content",rssFeedModel.content);
                    startActivity(intent);
 
                }
            });
 
 
               }
 
 
        @Override
        public int getItemCount() {
            return mRssFeedModels.size();
        }
    }
 
}

We have to define the layout used in every recyclerview post.

我们必须定义每个recyclerview帖子中使用的布局。

recycler_layout.xml

recycler_layout.xml

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
<TextView
    android:id="@+id/titleText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textStyle="bold" />
 
<TextView
    android:id="@+id/descriptionText"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
 
<View
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="@color/colorAccent" />
</LinearLayout>

Atlast we have to use our adapter in our onPostExecute method to distribute our list in recyclerAdapter.

最后,我们必须在onPostExecute方法中使用适配器以在recyclerAdapter中分发列表

mRecyclerView.setAdapter(new RssFeedListAdapter(mFeedModelList));

We have defined another activity which is called when we click on anycard of recyclerView which opens full content of a post in webView.

我们定义了另一个活动,当我们单击recyclerView的任何卡片时会调用该活动,从而在webView中打开帖子的完整内容。

activity_final.xml file

activity_final.xml文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".Final">
 
    <WebView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/web"/>
 
</android.support.constraint.ConstraintLayout>

And we have to define its java class too.

而且我们也必须定义其java类。

Final.java

Final.java

package com.example.anmol.rssdemo;
 
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
 
public class Final extends AppCompatActivity {
 
    WebView webview;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_final);
 
        webview=(WebView)findViewById(R.id.web);
        webview.getSettings().setJavaScriptEnabled(true);
        webview.loadData(getIntent().getStringExtra("content"),"text/html","UTF-8");
        webview.setWebViewClient(new WebViewClient());
 
    }
}
Android RSS Reader Tutorial

That’s all, now you can run your app in your physical device or in your emulator and see your rss feed in list format.

就是这样,现在您可以在物理设备或模拟器中运行应用程序,并以列表格式查看rss feed。

Comment below if you have any queries related to above android rss reader example.

如果您有任何与上述android rss阅读器示例相关的查询,请在下面评论。

翻译自: https://www.thecrazyprogrammer.com/2018/12/android-rss-reader-tutorial.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值