Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Android

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

5.00/5 (4 votes)
19 Apr 2011CPOL2 min read 39K  
Continued from: Android Lists: ListActivity and ListView I.

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

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

Java
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:

Java
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 it will be 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 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

Java
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));
    }
}
Java
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;
    }
}
Java
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
<?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
<?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>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)