Android Lists: ListActivity and ListView II – Custom Adapter and List Item View

Continued from: Android Lists: ListActivity and ListView I – Basic Usage

You’ve got a functioning list of stock ticker symbols now; however, it’s just a list of symbols and nothing more.  Let’s explore how to add a static stock quote to each of the ticker symbols.

First, you can design the layout of how the stock ticker and quote should appear in the list.  This is accomplished by creating a new layout file under res\layout.  The following shows a simple row layout with two TextViews placed side-by-side horizontally:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
		android:orientation="horizontal"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent">
	<TextView
		android:layout_width="wrap_content"
		android:layout_height="fill_parent"
		android:id="@+id/ticker_symbol"	/>
	<TextView
		android:layout_width="wrap_content"
		android:layout_height="fill_parent"
		android:id="@+id/ticker_price"	/>
</LinearLayout>

While you used the ArrayAdapter in the previous part, you can’t use that adapter here since it only accepts a layout that contains a single TextView.  One of the easiest and most flexible ways to use the layout that was just created is to create your own adapter by making a new class that extends from ArrayAdapter.

To do this, you can start by making a data class that will hold the stock quote information.  This class will be used as the type parameter to ArrayAdapter when you create your new adapter class.  I’ve provided a basic class below that holds the stock ticker and quote, along with getters and setters.

package com.austinrasmussen.stockviewer;

public class StockQuote {
	private String tickerSymbol;
	private double quote;

	public StockQuote(String tickerSymbol, double quote) {
		this.tickerSymbol = tickerSymbol;
		this.quote = quote;
	}
	public void setTickerSymbol(String tickerSymbol) {
		this.tickerSymbol = tickerSymbol;
	}
	public String getTickerSymbol() {
		return tickerSymbol;
	}
	public void setQuote(double quote) {
		this.quote = quote;
	}
	public double getQuote() {
		return quote;
	}
}

Now that you have a class to hold the stock quote data, you can create the custom adapter that will use that class.  The key behind extending ArrayAdapter is to override the ArrayAdapter.getView(…) method.  If this isn’t done, you will run into the limitation of the ArrayAdapter class that requires you to provide it with a layout that only contains a single TextView (i.e. java.lang.IllegalStateException: ArrayAdapter requires the resource ID to be a TextView).  I’ve put together an adapter class that will fulfill the requirements for this part of the series.

package com.austinrasmussen.stockviewer;

import java.util.List;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class StockQuoteAdapter extends ArrayAdapter {
	private final Activity activity;
	private final List stocks;

	public StockQuoteAdapter(Activity activity, List objects) {
		super(activity, R.layout.stock_quote_list_item , objects);
		this.activity = activity;
		this.stocks = objects;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View rowView = convertView;
		StockQuoteView sqView = null;

		if(rowView == null)
		{
			// Get a new instance of the row layout view
			LayoutInflater inflater = activity.getLayoutInflater();
			rowView = inflater.inflate(R.layout.stock_quote_list_item, null);

			// Hold the view objects in an object,
			// so they don't need to be re-fetched
			sqView = new StockQuoteView();
			sqView.ticker = (TextView) rowView.findViewById(R.id.ticker_symbol);
			sqView.quote = (TextView) rowView.findViewById(R.id.ticker_price);

			// Cache the view objects in the tag,
			// so they can be re-accessed later
			rowView.setTag(sqView);
		} else {
			sqView = (StockQuoteView) rowView.getTag();
		}

		// Transfer the stock data from the data object
		// to the view objects
		StockQuote currentStock = stocks.get(position);
		sqView.ticker.setText(currentStock.getTickerSymbol());
		sqView.quote.setText(currentStock.getQuote().toString());

		return rowView;
	}

	protected static class StockQuoteView {
		protected TextView ticker;
		protected TextView quote;
	}
}

The only step left to do is combine the stock quote data with the newly created StockQuoteAdapter class.  This will be done in the main StockList activity class that we started in the previous part of this series.  All that needs to be done here is to create an ArrayList of StockQuote objects, which will be used in constructing the StockQuoteAdapter.  The String array creation and list adapter code is now replaced with the following:

List stocks = new ArrayList();
stocks.add(new StockQuote("MSFT", 24.78));
stocks.add(new StockQuote("ORCL", 34.02));
stocks.add(new StockQuote("AMZN", 180.13));
stocks.add(new StockQuote("ERTS", 19.73));

setListAdapter(new StockQuoteAdapter(this, stocks));

You can now run the application and are presented with the following:

Well, that looks… quite ugly.  You’ll also notice that we’ve lost the font formatting when using the simple_list_item_1 layout.  This is because the simple_list_item_1 had some simple formatting applied to the single TextView in the layout.

In the next part I’ll go over layout and formatting in some more detail.  This will assist in readability and help clean up the view.

Final Code

package com.austinrasmussen.stockviewer;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.os.Bundle;

public class StockList extends ListActivity {

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        List stocks = new ArrayList();
        stocks.add(new StockQuote("MSFT", 24.78));
        stocks.add(new StockQuote("ORCL", 34.02));
        stocks.add(new StockQuote("AMZN", 180.13));
        stocks.add(new StockQuote("ERTS", 19.73));

        setListAdapter(new StockQuoteAdapter(this, stocks));
    }
}
package com.austinrasmussen.stockviewer;

public class StockQuote {
	private String tickerSymbol;
	private Double quote;

	public StockQuote(String tickerSymbol, Double quote) {
		this.tickerSymbol = tickerSymbol;
		this.quote = quote;
	}
	public void setTickerSymbol(String tickerSymbol) {
		this.tickerSymbol = tickerSymbol;
	}
	public String getTickerSymbol() {
		return tickerSymbol;
	}
	public void setQuote(double quote) {
		this.quote = quote;
	}
	public Double getQuote() {
		return quote;
	}
}
package com.austinrasmussen.stockviewer;

import java.util.List;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class StockQuoteAdapter extends ArrayAdapter {
	private final Activity activity;
	private final List stocks;

	public StockQuoteAdapter(Activity activity, List objects) {
		super(activity, R.layout.stock_quote_list_item , objects);
		this.activity = activity;
		this.stocks = objects;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View rowView = convertView;
		StockQuoteView sqView = null;

		if(rowView == null)
		{
			// Get a new instance of the row layout view
			LayoutInflater inflater = activity.getLayoutInflater();
			rowView = inflater.inflate(R.layout.stock_quote_list_item, null);

			// Hold the view objects in an object,
			// so they don't need to be re-fetched
			sqView = new StockQuoteView();
			sqView.ticker = (TextView) rowView.findViewById(R.id.ticker_symbol);
			sqView.quote = (TextView) rowView.findViewById(R.id.ticker_price);

			// Cache the view objects in the tag,
			// so they can be re-accessed later
			rowView.setTag(sqView);
		} else {
			sqView = (StockQuoteView) rowView.getTag();
		}

		// Transfer the stock data from the data object
		// to the view objects
		StockQuote currentStock = stocks.get(position);
		sqView.ticker.setText(currentStock.getTickerSymbol());
		sqView.quote.setText(currentStock.getQuote().toString());

		return rowView;
	}

	protected static class StockQuoteView {
		protected TextView ticker;
		protected TextView quote;
	}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
		android:orientation="horizontal"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent">
	<TextView
		android:layout_width="wrap_content"
		android:layout_height="fill_parent"
		android:id="@+id/ticker_symbol"	/>
	<TextView
		android:layout_width="wrap_content"
		android:layout_height="fill_parent"
		android:id="@+id/ticker_price"	/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
		android:orientation="vertical"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent">
	<ListView
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:id="@android:id/list" />
</LinearLayout>

Tags: , , , ,

This entry was posted on Saturday, April 2nd, 2011 at 10:18 pm and is filed under Android. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

6 Responses to “Android Lists: ListActivity and ListView II – Custom Adapter and List Item View”

webdesign May 11th, 2011 at 5:58 am

Quite neat post. I simply stumbled upon your weblog and desired to say which I possess actually preferred reading your blog posts. Anyhow I’ll be subscribing to your blog and I hope you post again quickly!

viki April 6th, 2012 at 12:25 am

Fantastic! neat & clear, thanks a lot for this post

Krunal Shah June 26th, 2012 at 1:37 am

Thanks for such a neat code! Helped me a lot!

Oscar December 14th, 2012 at 3:17 pm

Very good, this helped me a lot! I didn’t have a clue how displaying lists worked before reading this.

Nivetha January 28th, 2013 at 2:30 am

thanks a lot!!!really helped me to clear my doubt

Manish March 5th, 2013 at 11:23 am

Hi,

Thanks for this wonderful series.But i got 2 error while using the above code.

1. List stocks should be changed to List stocks.

2.In StockQuote class , you have declared quote as Double and yet you are assigning it a string.
sqView.quote.setText(currentStock.getQuote().toString());

I think this should also be changed.
Please correct me if i am wrong.

Leave a Reply

You must be logged in to post a comment.