It all started with a very simple wish that I wanted to create a list like this:
Each list entry has two lines and the lines are styled differently. Fortunately, there is an example program at the ListActivity documentation page which happens not to work and takes the input behind the list from a database. So it took me some time to find my friend, the SimpleAdapter widget and to find out, how to use it.
You can download the example program from here.
The root of the problem is that each element of this list is a complex view, consisting of two TextViews (XML mangling because of blog engine limitations):
[?xml version="1.0" encoding="utf-8"?]
[LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"]
[TextView android:id="@+id/text1"
android:textSize="16px"
android:textStyle="bold"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/]
[TextView android:id="@+id/text2"
android:textSize="12px"
android:textStyle="italic"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/]
[/LinearLayout]
The corresponding SimpleAdapter maps an element from list of objects to this view.
SimpleAdapter notes = new SimpleAdapter(
this,
list,
R.layout.main_item_two_line_row,
new String[] { "line1","line2" },
new int[] { R.id.text1, R.id.text2 } );
Now this is not a trivial line of code. What it says is:
- "list" is a reference to an object implementing the List interface. Each element in this list is an object implementing the Map interface. In our implementation example, the list is ArrayList and the elements in this list are HashMaps.
- The layout describing one row in the main list is defined in layout/main_item_two_line_row.xml file.
- In each individual HashMap, there are two key-value pairs. The keys are "line1" and "line2", the corresponding values are arbitrary objects whose toString() method yields the value displayed in the list row. In our case, the values are Strings.
- Values stored with key "line1" will be displayed in the TextView whose id is "text1". Similarly, "line2" Map key is associated with "text2" TextView.
37 comments:
Thanks that was a really interesting example. I've been trying to get multi row, multi column lists working for a while, and you're right it’s not over documented. The one google example is not compileable.
Your code did not work out of the box for me. In the main_item_two_line_row.xml file I had to strip android: from before the keyword id to get it to compile.
TextView android:id="@+id/text1" changed to TextView id="@+id/text1" and in two other places.
That brought it in line with google’s simple list examples.
Now any advice on getting a single row, two column list to work?
Cheers, Francis
Do you use the latest emulator (m5-rc14)? If you don't, migrate as soon as possible. They have changed the schema and simple "id" does not work anymore.
Oh my god I'm retarded. I had it right, but what I was forgetting to do was add the new HashMap[String,String]s I was creating to the ArrayList! That would probably explain why no values were showing up.
Anyways; excellent article, thanks for jogging my brain.
Hi Gabor,
Thanks for the useful code snippet, it helped me to understand how Listboxes work on Android, too.
However, in order for the code to work on the latest SDK (1.0 R2) it required some patches:
- In onCreateOptionsMenu method menu.add(...) had to be introduced by another argument like this:
menu.add(0, ADD_ITEM_ID, 0, R.string.add_item );
- onOptionsItemSelected didn't work as is, either, and I found that you'd probably use onMenuItemSelected instead. And its first two lines would look like this:
public boolean onMenuItemSelected(int featureId, MenuItem item) {
switch ( item.getItemId() ) {
You might wish to adjust your code according to these findings or not ... it's really up to. :)
Thanks again!
This example is very useful. I am just starting to dabble in Android and I encountered the same problem with the ListView. I wanted to have a multi-row,multi-colum list view and this blog just solved it for me.
Excellent article!
You don't need to instantiate a new notes object for each new item.
Here's my modified addItem method:
private void addItem() {
long ts = System.currentTimeMillis();
int lastDigit = (int)( ts % 10 );
HashMap item = new HashMap();
item.put( "line1",Long.toString( ts ) );
item.put( "line2","lastDigit: "+Integer.toString( lastDigit ) );
list.add( item );
notes.notifyDataSetChanged();
}
Keep onCreate the same and make notes a class variable. I think this is closer to the intent of the adapter.
Thanks, Mark, you are right. I updated the sample program.
It was just about time, this sample program from 2008 March did not compile with the standard SDK. :-)
hi, i have downloaded this code and when i ran this code on my machine it says no items found could you please help how to add items??
i am new to android
and i want to make it click able to show details of records..
Anonymous: Menu/Add item :-)
sorry i did not understand could you please tell me in detail i am new to android....
ok friend got it...
on clicking menu then add item appears LOL..
thanks..
i have one more question
if i try to run additem() function on oncreate function
it does not do anything..
for testing i want to add two or three items on loading activity
what you suggest what should i do???
Try this:
Test-driving the Android GUI
nevermind. erase previous post and this one. thank you.
thanks a lot!!!!!!!!!!
This tutorial has saved my lot of time.
Thanks really.
hi,
nice tutorial!! saved me lot of time! thx!
but i have one more question: how to pass some attributes to each row? such as bgColor or height?
thx!
tom
Anonymous, check this post. Be careful, that example program was written for pre-1.0 SDK, it needs some updating. The instructions are in the comments of the post.
Great tutorial, thanks. I was wondering if you have tried the android HelloSpinner, it uses an arrayAdapter, and I have a heck of a time adding items into the arrayAdapter. The adapter.Add method does not seem to work based on all the posts out there....your input will be appreciated
Anonymous, many Android adapters have a trick that they don't refresh the widget tree (i.e. the visible elements) until they are instructed to do so. The magic method is notifyDataSetChanged() in android.widget.BaseAdapter (parent class for ArrayAdapter, e.g.) which conveniently has no documentation text in the Android reference (just the method headline). For ArrayAdapter, you also have setNotifyOnChange(). If you invoke when you set up your adapter, notifyDataSetChanged() will be invoked automatically when you add, delete or modify an element. If your widget that the adapter is attached to is already visible and you add a large amount of items then I don't recommend setNotifyOnChange( true ) as it causes visible flicker on screen.
This is a less documented part of adapters, I admit.
Thanks for the advice; actually it dies at the Add method, so I could not even get to the notifyDataSetChanged() that you mentioned. I plan to switch over using the database method instead of using the resource file option - HT
Anonymous, is multithreading involved somehow? Android widgets including adapters can only be manipulated from the app's ui thread. There are tricky ways to get multithreading into the picture, e.g. rpc.
Thank you, You saved my time.
This was a useful tutorial on SimpleAdapter.
SimpleAdapter was not as simple as I thought.
Thank for your sample code, it also need to use two line item for listview. Can u show me how to get value from selected item with your code? i can get selected value from a single row item listview. but with your code i can't. can u show me ?
thank, now i can get value from two line item with your code.
String str;
str=list.get(position).toString();
//list.remove(position); //notes.notifyDataSetChanged();
Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();
Thanx .. that really helped and saved a lot of effort of going through the not-working overly complex tutorials. :)
Thanks a lot for the great article.. very helpful and explanatory to beginners. Official documentation continue to strike me as useless in most cases.
I hope you don't mind me referencing your article in my blog.
Mohammed, of course I don't mind, thanks!
Thanks....
THANK YOU VERY VERY MUCH! I wasted 6 hours coding trying to get my list to work, finally I saw your information and got it working.
I had a small problem with notes.notifyDataSetChanged(); - it didn't seem to post the information to the list from a loop, but got around that pretty quickly.
Thank you again!
Thanks. I'm reading an article similar to this which links to your article. So I thought it is more convenient if I can read another article on this topic.
Thanks for helping us. This solved my issue.
Thanks a lot...
it helped alot... Thanking u again...
Hi friend, Your blogs are very cooperative and informative. pleasing information benefiting item. This mail is actually the best on this prized topic. "I actually relish to read all the content is dispatched on your blog. It's very simple to read, the content is large, and you’re an educated scribe different most of the blogs. thanks for the post.
tizen vs. android, may I recommend this forum?
Your Tizen-related comments would be welcome there.
AWESOME!!!!!!!!!!
If you have a problem with notifyDataSetChanged(), just delete "SimpleAdapter"
in
SimpleAdapter notes = new SimpleAdapter
new line
notes = new SimpleAdapter
This is because we have created a new variable in the class
private SimpleAdapter countries;
And if we create it again in oncreate method, then
we will get an error
Attempt to invoke virtual method 'void android.widget.SimpleAdapter.notifyDataSetChanged()' on a null object reference
Post a Comment