Android ListView with icons/images ….and “sharks with lasers”


Well what do they have in common ?……purely coincidence! I recently worked on a project that required a search functionality. The search however involved different categorized items.

I was thinking of a neat visual way to quickly distinguish between results from different categories. Totally COINCIDENTLY at that exact moment a colleague shouted …”sharks with lasers on their heads!”

Download : IconizedListView.zip

Some Notes:

  1. XML Parsing
  2. ArrayAdapter for modifying visual display of list items

File: listview.xml

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

File: country_listitem.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="wrap_content">

	<ImageView
		android:id="@+id/country_icon"
		android:layout_gravity="left"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content" />

	<TextView
		android:id="@+id/country_name"
		android:text="Country Name"
		android:paddingLeft="10dip"
		android:layout_weight="0.5"
		android:layout_gravity="center"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content" />
	<TextView
		android:id="@+id/country_abbrev"
		android:text="Country Abbrev"
		android:layout_gravity="right"
		android:paddingRight="10dip"
		android:layout_width="wrap_content"
		android:layout_height="wrap_content" />

</LinearLayout>

File: raw/countries.xml

<?xml version="1.0" encoding="utf-8"?>
<countries>
		<country name="Australia" abbreviation="au" region="Asia" />
		<country name="Austria" abbreviation="at" region="Europe" />
		<country name="Belgium" abbreviation="be" region="Europe" />
		<country name="Brazil" abbreviation="br" region="S. America" />
		<country name="Canada" abbreviation="ca" region="N. America" />
		<country name="China" abbreviation="cn" region="Asia" />
		<country name="Denmark" abbreviation="dk" region="Europe" />
		<country name="France" abbreviation="fr" region="Europe" />
		<country name="Germany" abbreviation="de" region="Europe" />
		<country name="Hong Kong" abbreviation="hk" region="Asia" />
		<country name="India" abbreviation="in" region="Asia" />
		<country name="Indonesia" abbreviation="id" region="Asia" />
		<country name="Italy" abbreviation="it" region="Europe" />
		<country name="Korea" abbreviation="kr" region="Asia" />
		<country name="Netherlands" abbreviation="nl" region="Europe" />
		<country name="Norway" abbreviation="no" region="Europe" />
		<country name="Portugal" abbreviation="pt" region="Europe" />
		<country name="Singapore" abbreviation="sg" region="Asia" />
		<country name="Spain" abbreviation="es" region="Europe" />
		<country name="Sweden" abbreviation="se" region="Europe" />
		<country name="Switzerland" abbreviation="ch" region="Europe" />
		<country name="Taiwan" abbreviation="tw" region="Asia" />
		<country name="United Kingdom" abbreviation="uk" region="Europe" />
		<country name="United States" abbreviation="us" region="N. America" />
</countries>

File: Main.java

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;

public class Main extends Activity {

	private List<Country> countryList= new ArrayList<Country>();
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		// Set the View layer
		setContentView(R.layout.listview);
		setTitle("TestIconizedListView");

		// Create Parser for raw/countries.xml
		CountryParser countryParser = new CountryParser();
		InputStream inputStream = getResources().openRawResource(
				R.raw.countries);
		
		// Parse the inputstream
		countryParser.parse(inputStream);

		// Get Countries
		List<Country> countryList = countryParser.getList();
		
		
		// Create a customized ArrayAdapter
		CountryArrayAdapter adapter = new CountryArrayAdapter(
				getApplicationContext(), R.layout.country_listitem, countryList);
		
		// Get reference to ListView holder
		ListView lv = (ListView) this.findViewById(R.id.countryLV);
		
		// Set the ListView adapter
		lv.setAdapter(adapter);
	}
}

File: Country.java

public class Country
	{
		public String name;
		public String abbreviation;
		public String region;
		public String resourceId;

		public Country()
			{
				// TODO Auto-generated constructor stub
			}

		public Country(String name, String abbreviation, String region, String resourceFilePath)
			{
				this.name = name;
				this.abbreviation = abbreviation;
				this.region= region;
				this.resourceId = resourceFilePath;
			}

		@Override
		public String toString()
			{
				return this.name;
			}
	}

File: CountryParser.java

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import android.util.Log;

public class CountryParser {

	private static final String tag = "CountryParser";
	private static final String FILE_EXTENSION= ".png";
	
	private DocumentBuilderFactory factory;
	private DocumentBuilder builder;
	private final List<Country> list;

	public CountryParser() {
		this.list = new ArrayList<Country>();
	}

	private String getNodeValue(NamedNodeMap map, String key) {
		String nodeValue = null;
		Node node = map.getNamedItem(key);
		if (node != null) {
			nodeValue = node.getNodeValue();
		}
		return nodeValue;
	}

	public List<Country> getList() {
		return this.list;
	}

	/**
	 * Parse XML file containing body part X/Y/Description
	 * 
	 * @param inStream
	 */
	public void parse(InputStream inStream) {
		try {
			// TODO: after we must do a cache of this XML!!!!
			this.factory = DocumentBuilderFactory.newInstance();
			this.builder = this.factory.newDocumentBuilder();
			this.builder.isValidating();
			Document doc = this.builder.parse(inStream, null);

			doc.getDocumentElement().normalize();

			NodeList countryList = doc.getElementsByTagName("country");
			final int length = countryList.getLength();

			for (int i = 0; i < length; i++) {
				final NamedNodeMap attr = countryList.item(i).getAttributes();
				final String countryName = getNodeValue(attr, "name");
				final String countryAbbr = getNodeValue(attr, "abbreviation");
				final String countryRegion = getNodeValue(attr, "region");

				// Construct Country object
				Country country = new Country(countryName, countryAbbr,
						countryRegion, countryAbbr + FILE_EXTENSION);
				
				// Add to list
				this.list.add(country);
				
				Log.d(tag, country.toString());
			}
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
	}
}

File: CountryArrayAdapter.java

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
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 CountryArrayAdapter extends ArrayAdapter<Country> {
	private static final String tag = "CountryArrayAdapter";
	private static final String ASSETS_DIR = "images/";
	private Context context;
	private ImageView countryIcon;
	private TextView countryName;
	private TextView countryAbbrev;
	private List<Country> countries = new ArrayList<Country>();

	public CountryArrayAdapter(Context context, int textViewResourceId,
			List<Country> objects) {
		super(context, textViewResourceId, objects);
		this.context = context;
		this.countries = objects;
	}

	public int getCount() {
		return this.countries.size();
	}

	public Country getItem(int index) {
		return this.countries.get(index);
	}

	public View getView(int position, View convertView, ViewGroup parent) {
		View row = convertView;
		if (row == null) {
			// ROW INFLATION
			Log.d(tag, "Starting XML Row Inflation ... ");
			LayoutInflater inflater = (LayoutInflater) this.getContext()
					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			row = inflater.inflate(R.layout.country_listitem, parent, false);
			Log.d(tag, "Successfully completed XML Row Inflation!");
		}

		// Get item
		Country country = getItem(position);
		
		// Get reference to ImageView 
		countryIcon = (ImageView) row.findViewById(R.id.country_icon);
		
		// Get reference to TextView - country_name
		countryName = (TextView) row.findViewById(R.id.country_name);
		
		// Get reference to TextView - country_abbrev
		countryAbbrev = (TextView) row.findViewById(R.id.country_abbrev);

		//Set country name
		countryName.setText(country.name);
		
		// Set country icon usign File path
		String imgFilePath = ASSETS_DIR + country.resourceId;
		try {
			Bitmap bitmap = BitmapFactory.decodeStream(this.context.getResources().getAssets()
					.open(imgFilePath));
			countryIcon.setImageBitmap(bitmap);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// Set country abbreviation
		countryAbbrev.setText(country.abbreviation);
		return row;
	}
}

36 thoughts on “Android ListView with icons/images ….and “sharks with lasers”

  1. Re-wrote this example:
    1. xml for listview of countries
    2. xml for each row item in listview with place holders for image, country_name, country_abbrev
    3. Customized ArrayAdapter for using Country object.
    4. Acessing image files in the assets/ directory using:
    // Set country icon usign File path
    String imgFilePath = ASSETS_DIR + country.resourceId;
    try {
    Bitmap bitmap = BitmapFactory.decodeStream(this.context.getResources().getAssets()
    .open(imgFilePath));
    countryIcon.setImageBitmap(bitmap);
    } catch (IOException e) {
    e.printStackTrace();
    }

  2. hi nice tutorial.

    If I have to add new flag and country_name in the list using notification is it possible.. ?
    It means create a notification and using notification send Flag and country name. when we press on notification that flag and country name added to above list view .

    Please reply me on shirkeshashi04@gmail.com

  3. Pingback: รวมลิงก์เป็นประโยชน์สำหรับการพัฒนาโปรแกรมบน Android « MagicKiat's Weblog

  4. W2Davids: Great tutorial. Trying to figure out how to capture list item clicks… implementing onListItemClick does not work for me. Any suggestions on how to tweak this?

    public void onListItemClick(ListView parent, View v, int position, long id) {
    Toast.makeText(this, “you have selected ” + position, Toast.LENGTH_SHORT).show();
    }

  5. Hi i m also trying similar kind of application whereas i m showing list of countries with their flags and it is working fine , but i want to display the details of the country when i m clicking corresponding flag or text, is there any idea or sample for this?

    thanks

  6. Not sure if you would reply back but I have a strange event happening with remaking this code. I have the exact code but on the array adapter class textview keeps giving me a null error. I have verified that there is data before putting inside textview. Is there anything special you did?. I have explored almost all the possibilities could you reply me back with any data you did on this matter.

  7. Greate turtorial, i.m using right now and was very very helpful, but i need to implement onListItemClick listener. need help

  8. Very good tutorial indeed but i have one query…
    Can any1 tell me that how to implement onClick method on images ( not list iteam),,,I want to implement method when user click on particular image and I can implement further actions by knowing which listiteam’s image was clicked….
    Thx in advance…

  9. I can not do this part :
    String imgFilePath = ASSETS_DIR + country.resourceId;
    try {
    Bitmap bitmap = BitmapFactory.decodeStream(this.context.getResources().getAssets()
    .open(imgFilePath));
    countryIcon.setImageBitmap(bitmap);
    } catch (IOException e) {
    e.printStackTrace();
    }

    please help me . I am beginner for android so tell me simple this part.

      • Sayfada editText alanı oluşturup, yazdıkça ülkeleri filtreleyen bir kısım yapmak mümkün mü acaba? Bir fikri olan varsa yazarsa sevinirim.

        Is it possible to create an editText and search countries by filtering? Normally from a simple array its eeasier but when we take the data from XML its getting more complicated.
        I would be grateful if someone gives an advice.
        Thanks

  10. Really good solution compared to a lot that are out there. I see myself replacing the XML with a database further down the line, and I’m able to just write code that creates a List from the db and it works without having to rewrite everything. Great code – but perhaps not good as an introduction for beginners – that said – I was able to follow the code and this is the first XML parser I’ve ever used

  11. The answer is yes by adding to the Main.java after lv.setAdapter(adapter);
    lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {

    }
    });

  12. i’m beginner in android. i have to add the calendar events in my calendar application. so give me tips and procedure and also some coding parts.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s