Rss Reader App Android Tutorial 1: ListView and ArrayAdapter

On May 8, 2013, in Android, by James Liu

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:

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.

ListView and ArrayAdapter with Data Array

ListView and ArrayAdapter with Data Array


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);
	}
}
Basic ListView and ArrayAdapter

Basic ListView and ArrayAdapter

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:

ListView and ArrayAdapter with Data Array

ListView and ArrayAdapter with Data Array

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.

Tagged with:  

33 Responses to “Rss Reader App Android Tutorial 1: ListView and ArrayAdapter”

  1. JJ says:

    Thanks, this is a great tutorial!

  2. Claudi says:

    Guess you missed one line in the last getView, or I missed something else?

    > LayoutInflater inflater = myContext.getLayoutInflater();

    Elsewise love it, very usefull, thanks!

  3. ignem says:

    In “PostItemAdapter” why in its constructor there no cast of GetView and no return cause it’s not void ?
    Thank you

    • James says:

      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.

      • ignem says:

        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

  4. reza moradi says:

    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

    • James says:

      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

  5. reza moradi says:

    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

  6. rezymo says:

    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

  7. Riley says:

    how do i use this in an appp that uses fragments

    • James says:

      That’s simple. First, move all UI layout into your fragment layout. After that, move all code from MainActivity to your Fragment class.

  8. darshan says:

    i buy your app and i m parse my feed and what can i do apps can unfortunately stopped.

  9. Nadeesh says:

    Thank u very much,Really helpful

  10. Mamman says:

    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

    • James Liu says:

      listData is the array containing data which will be bound on the PostItemAdapter. You can check code onCreate function

  11. Gaurav Sharma says:

    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.

    • James Liu says:

      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.

  12. ak says:

    how to filter the feed by keyword?

  13. Harsh Khubchandani says:

    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?

    • James Liu says:

      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.

  14. Frost says:

    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

  15. Mark says:

    Very good for rss feed tutorial on android, it’easy understand.
    Thanks you so much.

  16. Andy says:

    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

    • James Liu says:

      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

  17. -__- says:

    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..

    • James Liu says:

      Hi, don’t worry about the menu xml. I am using the default one which android studio creates for me at the beginning.

Leave a Reply

Free WordPress Theme

Premium WordPress Themes