This website uses cookies to ensure you get the best experience on our website. OK
50 Shares 11 comments

Android development guide part 2: create your own RSS reader

Attention all your aspiring programmers, we’ve got the second portion of our Android development series coming up for you. After our first part introduced you to the programming environment for Android, we’re going to show you how to setup your own RSS feed. We’ll be going over some more basic principles and concepts while we walk you through this tutorial.

LV1A3278
 © AndroidPIT

If you still have the “Hello AndroidPIT” app project from the first part of the series, you can continue to work with it, otherwise you’ll need to go ahead and start a new project in Android Developer Studio.

Rich Site Summary (RSS)

First of all, what is an RSS feed? Many of you read RSS feeds on the daily in a reader app either on your PC or mobile device. In order to program an app that can display an RSS feed, you should know a little bit of a background into what RSS actually is. Wikipedia gives a pretty good over of RSS.

For example, the RSS feed from AndroidPIT can be found here: http://www.androidpit.com/feed/main.xml

Simply put, RSS is an XML file. XML is made principally to be display text and are designed for machine readability. Our first goal is to write an app which calls upon the XML file of the AndroidPIT feeds and to display it appropriately in our “Hello AndroidPIT” app.

Represent the RSS Feed

Next, we’ll show you how to bring the XML file onto the screen of your Android device. We’ll be continuing on from our first app from the first part of the series and we’ll modify it for our purposes.

On Android, the layout is usually defined via XML. So, if you plan on spending a bit more time around on the development side of things with Android, it would be wise to invest a little time in learning XML as it is a format you’ll continually be using.

The layout is stored in the res / layout folder.  If you open up the fragment_main.xml in your project, you’ll be able to see the XML layout file along with a preview of it.

pi
Our project from the first part of the series.  / © AndroidPIT

We want to replace the “Hello AndroidPIT!” with our RSS Feed. In order to do this, we to give TextView an identifier on what we want it to show. In this case, the android: id attribute will do the trick:

<TextView
       android:id="@+id/rss_feed"
       android:text="@string/hello_world"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content" />

After we provide the Textview with an id, we have to find the ones we want to use and an add them to our Placeholder fragment segment. For this purpose we use the method findViewById. It should like this within the onCreateView method:

@Override
       public View onCreateView(LayoutInflater inflater, ViewGroup container,
               Bundle savedInstanceState) {
           View rootView = inflater.inflate(R.layout.fragment_main, container, false);
           mRssFeed = (TextView) rootView.findViewById(R.id.rss_feed);
           return rootView;
       }

To retrieve the RSS feed at the start of the app, we need the following onStart method:

@Override
       public void onStart() {
           super.onStart();
           InputStream in = null;
           try {
               URL url = new URL("http://www.androidpit.com/feed/main.xml");
               HttpURLConnection conn = (HttpURLConnection) url.openConnection();
               in = conn.getInputStream();
               ByteArrayOutputStream out = new ByteArrayOutputStream();
               byte[] buffer = new byte[1024];
               for (int count; (count = in.read(buffer)) != -1; ) {
                   out.write(buffer, 0, count);
               }
               byte[] response = out.toByteArray();
               String rssFeed = new String(response, "UTF-8");
               mRssFeed.setText(rssFeed);
           } catch (IOException e) {
               e.printStackTrace();
           } finally {
               if (in != null) {
                   try {
                       in.close();
                   } catch (IOException e) {
                       e.printStackTrace();
                   }
               }
           }
       }

If you don’t understand the source code, don’t worry and just copy and paste what we’ve done. To understand it in depth, you’ll need to take up Java and learn the programming language.

If you try running the app right now, it will begin to compile but will crash at some point.

In app development, it is necessary that you can learn how to deal with crashes and what exactly they mean. If you open logcat at the same time as you run your application, it will log all the messages and error messages output by the application. If you do it after running what we’ve done so far, you should have the following error message:

com.rockylabs.androidpitrss E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.rockylabs.androidpitrss, PID: 14367
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.rockylabs.androidpitrss/com.rockylabs.androidpitrss.MainActivity}:
android.os.NetworkOnMainThreadException

So, what happened? Your application tried in the main thread to access the Internet, however, if the request takes too long, the application stops responding and an error message is issued. To avoid this, Android has been rigged to crash instead of hang indefinitely.

On Android, we’ll need to work in a world of asynchronous workflows. This means that when a requests is made to the system, it will run in the background and a notification will be returned to your as soon as the task is complete. This why, you know when your threads (threads of execution) are working and learn from it.

The standard in all tasks is the user interface thread, called UI thread for shot. In our case above, if you’re trying to access the internet and the server request takes too long, the interface gets hung up and cannot continue. As a result you get an Android error message that the application is not responding. This warning is also known as Application Not Responding (ANR). These type of messages should be avoided at all costs for reasons of user-friendliness.

anr dialog
© Creative Commons Attribution 2.5

Android provides a very simply way to handle this problem in the form of a different class called AsyncTask. You can then run a task in a background thread and run the result to the UI thread.

So, in our app, we want a to run a task with AsyncTask in the background. In the previous step, we have the source code for the onStart method inserted into our code. Now we need to separate the network and user interface, which is why we have created the method getAndroidPitRssFeed. This makes it easier to use source code several time rather than spending a lot of time copying and pasting. The getAndroidPitRssFeed method looks like this:

       private class GetAndroidPitRssFeedTask extends AsyncTask<Void, Void, String> {

           @Override
           protected String doInBackground(Void... voids) {
               String result = "";
               try {
                   result = getAndroidPitRssFeed();
               } catch (IOException e) {
                   e.printStackTrace();
               }
               return result;
           }

           @Override
           protected void onPostExecute(String rssFeed) {
               mRssFeed.setText(rssFeed);
           }
       }

If we re-run the app, we will again produce a crash but this time will not because of a lack of authoruization as opposed to timing out. We haven’t set any permissions to access the Internet and as such, we cannot obtain the RSS feed.

If you had logcat open while running the app the last time, you’ll see the following entry:

Caused by: java.lang.SecurityException: Permission denied (missing INTERNET permission?)

To set the Internet permissions, you’ll need to open the AndroidManifest.xml file. There you should see the following lines of code:

<uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="19" />

 
We will add the following line below them:
 

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

 
And voila! If you run the application, you’ll see that your App will run and start showing the XML of our RSS feed. As you certainly noticed, this will take some time to load. The entire feed is currently being loaded which can be a bit cumbersome. Later, we’ll show you how we can improve the user experience further by installing a progress indicator.
 
So far, so good. This is a definitely a moment to savor: grab a coffee, pat yourself on the back, and get a good stretch in: you’ve completed your first objective of displaying the RSS feed of AndroidPIT on a mobile device.


However, nobody wants to look at the gibberish that is known as XML format, so we’ll need to clean that up a bit. As well, we cannot go past the edge of the screen and are unable to scroll down at this point.

ScrollView

The solution to the above problem is to add the scrollview component that is already available in the Android SDK:

<ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/rss_feed"
            android:text="@string/hello_world"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </ScrollView>

In the next step, you will learn how the XML file is read so that we can modify it a bit and extract the titles of articles and present them in a list, so it is much cleaner for people to view.

android entwickler studio teil zwei rss 01
The fruits of our labors: XML displayed without being able to scroll. / © AndroidPIT

XML reading

Our next goal is to make the title of each article, inside the <title> tags, be displayed. If we look at the RSS feed (above image), it is found inside the <rss> portion of the code and right after the <channel> tag. For simplicity, we’ll just ignore all the other tags for now. Once we have worked through the whole XML file, we’ll have a better understanding of what they’re used for.

In order to handle an XML file, we need to search the mumbo jumbo and pull the information that we require from it. Fortunately for us, somebody has already created a tool that does this for us. As such, we will use a parser to extract the information that we need and will use XmlPullParser from the Android SDK.

The analysis of the XML file will go in the following stages:

START_DOCUMENT is for the beginning of the document, when the parser has yet to read anything yet.

START_TAG is what starts the parser

TEXT is when the parser is busy with content

ENG_TAG is when the parser is on the end tag

END_DOCUMENT is when the document is over and there is no more parsing options available.

First, we need the parser to create:

         XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
         XmlPullParser xpp = factory.newPullParser();

Then we have to give the parser a source to parse. We assign it to the string which we’ve downloaded from the server and are currently displaying via TextView.

As we previously mentioned, we want to read the RSS feed, channel, open item, and title tags in order to read the title of the article.  We will ignore all the rest. So we add readRSS, read channel, ReadItem, and read title. We’ll do that by issuing the following code:

private List<String> readRss(XmlPullParser parser)
                    throws XmlPullParserException, IOException {
                List<String> items = new ArrayList<>();
                parser.require(XmlPullParser.START_TAG, null, "rss");
                while (parser.next() != XmlPullParser.END_TAG) {
                    if (parser.getEventType() != XmlPullParser.START_TAG) {
                        continue;
                    }
                    String name = parser.getName();
                    if (name.equals("channel")) {
                        items.addAll(readChannel(parser));
                    } else {
                        skip(parser);
                    }
                }
                return items;
            }

Now we need to implement read channel to read out the contents, the rest we will leave aside!:

private List<String> readChannel(XmlPullParser parser)
                    throws IOException, XmlPullParserException {
                List<String> items = new ArrayList<>();
                parser.require(XmlPullParser.START_TAG, null, "channel");
                while (parser.next() != XmlPullParser.END_TAG) {
                    if (parser.getEventType() != XmlPullParser.START_TAG) {
                        continue;
                    }
                    String name = parser.getName();
                    if (name.equals("item")) {
                        items.add(readItem(parser));
                    } else {
                        skip(parser);
                    }
                }
                return items;
            }

ReadItem is also necessary:

private String readItem(XmlPullParser parser) throws XmlPullParserException, IOException {
                String result = null;
                parser.require(XmlPullParser.START_TAG, null, "item");
                while (parser.next() != XmlPullParser.END_TAG) {
                    if (parser.getEventType() != XmlPullParser.START_TAG) {
                        continue;
                    }
                    String name = parser.getName();
                    if (name.equals("title")) {
                        result = readTitle(parser);
                    } else {
                        skip(parser);
                    }
                }
                return result;
            }

Almost there, we just have get read title to pull the title:

            // Processes title tags in the feed.
            private String readTitle(XmlPullParser parser)
                    throws IOException, XmlPullParserException {
                parser.require(XmlPullParser.START_TAG, null, "title");
                String title = readText(parser);
                parser.require(XmlPullParser.END_TAG, null, "title");
                return title;
            }

And the text in the <title> day :

           private String readText(XmlPullParser parser)
                    throws IOException, XmlPullParserException {
                String result = "";
                if (parser.next() == XmlPullParser.TEXT) {
                    result = parser.getText();
                    parser.nextTag();
                }
                return result;
            }

With this method, the rest of the tags will be skipped:

           private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
                if (parser.getEventType() != XmlPullParser.START_TAG) {
                    throw new IllegalStateException();
                }
                int depth = 1;
                while (depth != 0) {
                    switch (parser.next()) {
                        case XmlPullParser.END_TAG:
                            depth–;
                            break;
                        case XmlPullParser.START_TAG:
                            depth++;
                            break;
                    }
                }
            }

Now you are almost professionals what the XML parsing concerns! In the next step we will issue the title of the item in a list.

List Fragment

In the Android SDK there is a class called list fragment that will help us with handling lists.

Since we already have a list of text strings, which we have extracted from the XML file, we can use a practical standard feature of Android with the adapter to represent the title. An adapter is a kind of bridge between the data that we want to present and the TextViews which represents the data.

With an adapter, we can use a TextView create method for each title from our list. You must use Placeholder fragment to accomplish this:

   public static class PlaceholderFragment extends ListFragment {

Finally, we must still use AsyncTask to be adapted so that our parser can work

            @Override
            protected List<String> doInBackground(Void... voids) {
                List<String> result = null;
                try {
                    String feed = getAndroidPitRssFeed();
                    result = parse(feed);
                } catch (XmlPullParserException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return result;
            }

            @Override
            protected void onPostExecute(List<String> rssFeed) {
                    setListAdapter(new ArrayAdapter<>(
                            getActivity(),
                            android.R.layout.simple_list_item_1,
                            android.R.id.text1,
                            rssFeed));
            }

If you try running your app now, you should first see a progress indicator while the RSS feed is downloaded from the server and then a list of all the titles from the feed will be shown as below.

android entwickler studio teil zwei rss 04
And there we go! A progress indicator and the title from the XML file. / © AndroidPIT

Summary

WHEW. We know that this guide is long and extensive and a big step compared to our first exercise. But if you have managed to get through of the entire thing, you should be very proud of what you’ve done and amazed on how much you’ve learned. Even if you haven’t understood every single minute detail, your understanding on how to program within Android will grow over time. The more you practice with Android development, the better you’ll come to understanding these type of things.

Our self-programmed feed reader works, but is not very useful as it currently just shows the article titles. So, in our next exercise, we’ll extend the functionality and make it so that we can read the introduction of our articles when we tap on the title.

What do you think? What improvements would you like to see in the RSS app tutorial? Let us know if the comments!

11 comments

Write new comment:
  • It would be more awesome if the tutorial had a second part teaching feed images and push notifications on new feeds. Awesome tutorial!

  • Thanks

  • Hello, I know this an old article, but im hoping someone out there will be able reply.

    I seem to be missing a couple of steps, and ive gone over the tuts several times.

    1/ No correlation from part 1 and part 2, because in the beggining of part 2, you start to talk about a fragment placeholder. although i tried to follow the tut correctly, im not sure its 100%

    so at the end of it, the getAndroidPitRssFeed, and mRssFeed do not resolve.

    Is the fragment code missing?

    Also, the link to download the source code is no longer working.

    Thanks.... newbie :)

  • How can i add descriptions to the list? Or make the headlines clickable to read descriptions?

  • How do I download te source code??

  • How do I download te source code??

  • JonatanPN Apr 14, 2014 Link to comment

    Hello, great tutorial about how make and app with RSS.

    My app work after download your source code because in the tutorial no appear where I have to enter the codes.

    I want know if you on the next month go to make the 3rd part for open the posts.

    and also I have some suggestions.

    1.Miniature of image what are on the topic.

    2. See what articles are read or not and option for mark all as read

    3. Push notifications when new topic are published and the users can select when want update if are or not news topics.

    You can use "feed.nu" for make an app with this options, but i want make by me with an appear design.

    Regards and great work.

  • Kuoyhout Feb 12, 2014 Link to comment

    please create a android development guide about the effective & best way to load image from website or link, handle it while it is loading, & display it in grid view or list view on slow device without crash

  • If you been working on this, here's a link to the app's source code posted by Henrique:
    https://github.com/HenriqueRocha/AndroidPITRSS

  • Hi, Henrique! Nice, simple yet very practical tutorial. Thank you for your effort ;-)

    Found a typo: "This why, you know when your threads (threads of execution) are working and learn from it." should be "This *way*, you know when your threads (threads of execution) are working and learn from it.".

This website uses cookies to ensure you get the best experience on our website. More info

Got it!