Working on a real project is the best way to learn a new programing language. In this tutorial, I will create a RSS Reader application for android step by step. This android application will read rss feed from the website, parse the xml and show all the post in a ListView. So we will cover following android development knowledge:
- Android Rss Reader Example 1: How to Use ListView and ArrayAdapter
- Android Rss Reader Example 2: Load Data by HTTP Request in Android
- Android Rss Reader Example 3: Parse XML in Android
- Android Rss Reader Example 4: Drag to Refresh ListView
- Android Rss Reader Example 5: Show WebSite Content in WebView
- Advanced Tutorial 6: Load Featured Image In ListView From Rss Feed
- Advanced Tutorial 7: Add Android Navigation Drawer Menu
In this android app example, I will implement a ListView which can show all the post entities from Rss feed. For each list cell view, there are three components, ImageView which is for post featured image, TextView which is for post title, and another TextView which will show post date.
My working environment is Eclipse 3.7.2, with ADT 21.1.0 and Android SDK r21.1. I will create a project with minimum SDK Android 2.2 and target SDK Android 4.2. After several configuration, we will get empty project which has a “Hello World” on the screen.
ListView and ArrayAdapter Basic Example
ListView is one type of AdapterView, which can populate a list of scrollable items, by binding to an Adapter. In my example, I will use ArrayAdapter to hold the data and return a View which represents each data entry. Usually, we can use ArrayAdapter when data are formed by Array. If our data comes from a Cursor, we can use SimpleCursorAdapter instead.
Android Custom ListView with Text
In the beginning of this tutorial example, I will put a TextView in ListView. Android provides us a very big space to customize ListView item such as customizing the layout, styling the text etc. In the below layout source code, I will put a ListView in the RelativeLayout and use the basic ArrayAdapter to render the View for list. Now let’s see the code example:
<!-- activity_postlist.xml --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity" > <ListView android:id="@+id/postListView" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </RelativeLayout>
<!-- postitem.xml --> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/postTitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:maxLines="2" android:textIsSelectable="false" android:textSize="16sp" > </TextView>
package com.jms.rssreader; import android.os.Bundle; import android.app.Activity; import android.widget.ArrayAdapter; import android.widget.ListView; public class MainActivity extends Activity { private String[] listData = new String[]{"Post 1", "Post 2", "Post 3", "Post 4", "Post 5", "Post 6"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_postlist); ListView listView = (ListView)this.findViewById(R.id.postListView); ArrayAdapter<String> itemAdapter = new ArrayAdapter<String>(this, R.layout.postitem, listData); listView.setAdapter(itemAdapter); } }
Customize List Cell View with Value Object
In the above basic ListView example, I pre-defined a string array with six entities and render a sample list with six cells. In real application, it is far from usage. In this step, I will customize the list cell view to show more information, such as post image, post title and post date. Meanwhile, I will create a more complex data to render the list. (In next post, I will load the data from real Rss feed instead of run time rendering). In the end, the new app will look like:
Android Custom ListView with Images and Text
As the above figure, I will customize the ListView with more Android components. First, I will add an ImageView in the left of each ListView item. Then, I will add two TextView align with the image component. For the top text, I will style the text with big font and 2 lines. For the bottom text, I will make the font smaller than the top one. Here is our customized ListView source code example. In the layout xml, I add one ImageView and two TextView in RelativeLayout.
<!-- postitem.xml --> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="16dp" android:paddingRight="16dp" android:paddingTop="5dp" android:paddingBottom="5dp" > <ImageView android:id="@+id/postThumb" android:layout_width="60dp" android:layout_height="60dp" android:src="@drawable/postthumb_loading" android:scaleType="centerCrop" android:layout_marginRight="5dp"/> <TextView android:id="@+id/postTitleLabel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignTop="@id/postThumb" android:layout_toRightOf="@id/postThumb" android:maxLines="2" android:text="This is a good Post, I hope it will have 2 lines. Please give me 2 lines" android:textIsSelectable="false" android:textSize="16sp" android:ellipsize="end"/> <TextView android:id="@+id/postDateLabel" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignBottom="@id/postThumb" android:layout_toRightOf="@id/postThumb" android:maxLines="1" android:text="April 12, 2013" android:textSize="12sp" /> </RelativeLayout>
I create a new value object to hold post data for each post from RSS Feed.
/** * PostData.java * * Value Object */ package com.jms.rssreader.vo; public class PostData { public String postThumbUrl; public String postTitle; public String postDate; }
For complicated data and list cell view, we need to implement a new adapter class which inherit from ArrayAdapter and override the function getView to get the list cell view. Here is the example code.
/** * PostItemAdapter.java * * Adapter Class which configs and returns the View for ListView * */ package com.jms.rssreader.adapter; import com.jms.rssreader.R; import com.jms.rssreader.vo.PostData; import android.app.Activity; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; public class PostItemAdapter extends ArrayAdapter<PostData> { private Activity myContext; private PostData[] datas; public PostItemAdapter(Context context, int textViewResourceId, PostData[] objects) { super(context, textViewResourceId, objects); // TODO Auto-generated constructor stub myContext = (Activity) context; datas = objects; } public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = myContext.getLayoutInflater(); View rowView = inflater.inflate(R.layout.postitem, null); ImageView thumbImageView = (ImageView) rowView .findViewById(R.id.postThumb); if (datas[position].postThumbUrl == null) { thumbImageView.setImageResource(R.drawable.postthumb_loading); } TextView postTitleView = (TextView) rowView .findViewById(R.id.postTitleLabel); postTitleView.setText(datas[position].postTitle); TextView postDateView = (TextView) rowView .findViewById(R.id.postDateLabel); postDateView.setText(datas[position].postDate); return rowView; } }
Now, let’s see the main class. Instead of using ArrayAdapter and string array, I generate a temporary data for our new ListView.
package com.jms.rssreader; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.widget.ListView; import com.jms.rssreader.adapter.PostItemAdapter; import com.jms.rssreader.vo.PostData; public class MainActivity extends Activity { private PostData[] listData; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_postlist); this.generateDummyData(); ListView listView = (ListView) this.findViewById(R.id.postListView); PostItemAdapter itemAdapter = new PostItemAdapter(this, R.layout.postitem, listData); listView.setAdapter(itemAdapter); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } private void generateDummyData() { PostData data = null; listData = new PostData[10]; for (int i = 0; i < 10; i++) { //please ignore this comment :> data = new PostData(); data.postDate = "May 20, 2013"; data.postTitle = "Post " + (i + 1) + " Title: This is the Post Title from RSS Feed"; data.postThumbUrl = null; listData[i] = data; } } }
Android ListView Performance
Now, I will talk about the performance of Android ListView. In above example, I generate 10 list entities. However, the app will get slower and slower when there are more data in the data list. In the adapter class, we inflate a new View object for each coming data entity. This approach is very expensive. To make this android ListView fast and efficient, we can improve the Adapter class and reuse some cell view. There are two ways to make it fast.
Improve ListView Performance by Using Recycling Views
Using the recycling view will be more efficient than instantiating a new view each time. Usually, the android ListView performance will be increased by 2 times. Here is the improved getView function in adapter class.
public View getView(int position, View convertView, ViewGroup parent) { View rowView; if(convertView == null) { LayoutInflater inflater = myContext.getLayoutInflater(); convertView = inflater.inflate(R.layout.postitem, null); } rowView = convertView; ImageView thumbImageView = (ImageView) rowView .findViewById(R.id.postThumb); //check if the datas[position].postThumbUrl is null if (datas[position].postThumbUrl == null) { thumbImageView.setImageResource(R.drawable.postthumb_loading); } TextView postTitleView = (TextView) rowView .findViewById(R.id.postTitleLabel); postTitleView.setText(datas[position].postTitle); TextView postDateView = (TextView) rowView .findViewById(R.id.postDateLabel); postDateView.setText(datas[position].postDate); return rowView; }
The Best Way to Improve Android ListView Performance by ViewHolder
After we use the recycling views in the ListView, the performance of the new app has a clear improvement. However, there is more space for use to improve. findViewById function call is another expensive operation. We can avoid it by using ViewHolder. It is a static class which will hold the references of each cell view’s objects. Hence, we can get the objects in cell view directly by reference directly, instead of calling findViewById. Here is the third variation of getView function.
static class ViewHolder { TextView postTitleView; TextView postDateView; ImageView postThumbView; } public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { LayoutInflater inflater = myContext.getLayoutInflater(); convertView = inflater.inflate(R.layout.postitem, null); viewHolder = new ViewHolder(); viewHolder.postThumbView = (ImageView) convertView .findViewById(R.id.postThumb); viewHolder.postTitleView = (TextView) convertView .findViewById(R.id.postTitleLabel); viewHolder.postDateView = (TextView) convertView .findViewById(R.id.postDateLabel); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } if (datas[position].postThumbUrl == null) { viewHolder.postThumbView .setImageResource(R.drawable.postthumb_loading); } viewHolder.postTitleView.setText(datas[position].postTitle); viewHolder.postDateView.setText(datas[position].postDate); return convertView; }
Load Image in ListView Tutorial
In this tutorial guide, I just demonstrate how to customize ListView with images and text. But in the example, I am only using a static image to make it easy to understand. After you successfully create a custom ListView, you’d better to read following artile about how to dynamically load image into ListView.
Download Images by AsyncTask in ListView Android Example
More Complicated Customization
For different project, the requirement may not be the same. Some application may request to add more Android components in the ListView, for example, a button which can handle users clicking. For this more complicated customization, I recommend you to read following articles.
Customize Android ListView Item Layout Style Tutorial
This tutorial gives an example to customize the ListView with image, text and button.
Click Button in ListView And Get Item Position
This example will show you how to handle user clicking button inside ListView. It is quite a complete guide for you to get where the users click.
Next: Load Data by HTTP Request in Android
The example performs quite great. However, we are still using fake data to generate the tables. To get the real data in Android, we will talk about HTTP Request and download data in next post.
Go to next tutorial: Loading data from internet in Android.
good one
Thanks, this is a great tutorial!
Guess you missed one line in the last getView, or I missed something else?
> LayoutInflater inflater = myContext.getLayoutInflater();
Elsewise love it, very usefull, thanks!
Yes, you are right. Thank you for your feedback.
In “PostItemAdapter” why in its constructor there no cast of GetView and no return cause it’s not void ?
Thank you
Hello,
There is “GetView” function in PostItemAdapter class. I don’t know what you mean “there is no cast of GetView in its constructor”. GetView is a function in PostItemAdapter.
sorry but i think i work too late last night, i made an error in the name of my class and eclipse tell me weird thing -.- …
That working now thank you
i do not know how can i give package com.jms.rssreader.vo; in my project ?
pleas help me.
when i creat PostData in intealij it s gave me error and say me this package unexisted
Do you know what package means in Java? To create this package, you need to create the folder com/jms/rssreader/vo. Then, put your class PostData in the vo folder. I hope I answer your question correctly. Any questions, just let me know.
Best Regards
James Liu
pleas forgive me because my above world .i see not your answer first and i think you do not answer me . but resolve my problem finally.tank you for help me
pleas forgive me because my above world .i see not your answer first and i think you do not answer me . but resolve my problem finally.tank you for help me
how do i use this in an appp that uses fragments
That’s simple. First, move all UI layout into your fragment layout. After that, move all code from MainActivity to your Fragment class.
i buy your app and i m parse my feed and what can i do apps can unfortunately stopped.
What’s error message you get in your eclipse?
Thank u very much,Really helpful
Hello James, I’m not very vast with android coding. please can you explain lines 42 and 46, I have no idea what these listData[i] = data; stands for. Thanks alot in advance
listData is the array containing data which will be bound on the PostItemAdapter. You can check code onCreate function
Hello Sir,
The last method to increase the efficiency i.e. the ViewHolder was giving me an error. After debugging I found that error was due to java.lang.NullPointerException. Then I inserted a try catch and the program was working fine after that. Can you please explain why this is happening?
Thank You.
I think you should told me which line you get the error. Most of the case, you are writing something wrong. As above code is testing by my visitors over thousands.
how to filter the feed by keyword?
You have to use other rss feed plugin
Is there one you recommend or will http://jmsliu.com/2764/add-android-navigation-drawer-menu-into-rss-reader-app.html get the job done.
That’s the final app. If you just want to get the final app, you can check this article.
I have successfully made all classes and packages but when I run it in my device and launch app a blank screen appears and it closes.
Secondly, what about main.xml in menu folder?
I guess you made something wrong. That’s why your app closes without anything. You’d better check your debug window and find out the error message. It will be helpful.
This is awesome, however i want to get posts from a website using wordpress, how do i customise this tutorial for that ?? please respond using email, this will be my first mobile app in the store so i need some good answer, thanks
Actually, I have a full tutorial about how to create a rss feed tutorial with wordpress website. Please check this article, Android Mobile App for Website powered by WordPress.
Very good for rss feed tutorial on android, it’easy understand.
Thanks you so much.
Hello,
is it possible to read the rss feed from a joomla 3 site?
I´ve buy your app, but when i change the feed url in global class,
the content is not visible and behind the output url attached a 1, so the content in the app will not found.
I wish that every menu point have a single feed url, is this possible?
Great tutorial,
thanks for answers…
Andy
First, Joomla 3 site may have different different url to get the rss feed. Second, you have to make sure that the rss feed xml format is correct. Third, if you want every menu pointing to a single feed url, you have to chang the code a little bit (more complicated than I said here)
Best Regards
James
What you can view folder menu and code xml?
you not publish folder menu your website,
getMenuInflater().inflate(R.menu.main, menu);
Sorry bad english..
Hi, don’t worry about the menu xml. I am using the default one which android studio creates for me at the beginning.
Thank you for writing a good article
You are welcome. I am glad you like it.
Thanks, helped alot.