Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attaching ID data to listview items

Tags:

android

I have an application that fetches announcements stored as xml files on a server and loads the title and author of each announcement into a ListView item. What I also need to store with each item is the ID of each announcement but I don't actually need to display it. I thought about maybe storing the ID in the hash map I use to fill the list and then find the associated ID with the title clicked but I think it would be unsafe to use since two announcements could have the same title (and author and date). I also thought about adding an invisible TextView to each item to store the ID but that was causing layout problems. Lastly, I searched around and found setTag() and getTag() which I think would be perfect for what I want to do but I'm not really sure how to use them with SimpleAdapter (I'm relatively new to this...). If the TextView idea is what I need to do (though I doubt it), here is the layout I'm using for each item:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical" >

    <TextView
      android:id="@android:id/text1"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:layout_marginLeft="6dip"
      android:textAppearance="?android:attr/textAppearanceMedium"/>
    <LinearLayout 
        android:orientation="horizontal"
        android:id="@+id/items"
        android:weightSum="100"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">
        <TextView
          android:id="@android:id/text2"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_marginLeft="6dip"
          android:textAppearance="?android:attr/textAppearanceSmall"
          android:layout_weight="85"/>
        <LinearLayout 
            android:orientation="vertical"
            android:id="@+id/itemCB"
            android:layout_weight="15"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center">
            <CheckBox
                android:id="@+id/cbSelected"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

And I'm using the following adapter to fill the list:

for(int i = 0; i < ann.length; i++)
{
    map = new HashMap<String, String>();
    map.put("line1", ann[i].getTitle());
    map.put("line2", "Posted by: " + ann[i].getAuthor() + "\n" + ann[i].date.toLongString());
    list.add(map);
}
String[] from = { "line1", "line2"};

int[] to = { android.R.id.text1, android.R.id.text2};

SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.twoline_checkbox_id_listitem, from, to);
setListAdapter(adapter);

Thank you for any help!

like image 473
lancex Avatar asked Dec 30 '11 01:12

lancex


2 Answers

Theoretically you could do either approaches and it will probably work without problems. In the long run however, I would say you'll be better of with a simple entity object and a custom adapter. More specifically, from the looks of it, I would opt for an ArrayAdapter, and you already seem to be using some sort of simple entity object for the array ann.

There are tons of examples that can show you how to extend ArrayAdapter. The most important part however is the getView() method, which in it's most basic form could look somewhat like this:

public View getView(int position, View convertView, ViewGroup parent) {
    View row;
    if (null == convertView) {
        row = mInflater.inflate(R.layout.list_item, null);
    } else {
        row = convertView;
    }

    MyObject item = (MyObject) getItem(position);

    TextView tv = (TextView) row.findViewById(android.R.id.xxx);
    tv.setText(item.getTitle);

    // same for other fields/views; e.g. author, date etc

    return row;
}

In stead of creating a SimpleAdapter, now create an instance of your CustomAdapter, pass it your array (or list) of entity objects, and set the whole as adapter to your list:

MyObject[] objects = ...
setListAdapter(new ArrayAdapter<string>(this, R.layout.list_item, objects));

Since you're now dealing with the objects directly, in stead of first creating a bunch of strings representation out of the different fields, you can also easily access the 'id' of every item. Even better, you can add a whole lot of different fields without worrying how it will look like in the list, since the visual representation is determined by what you set (and don't set) in the getView() method of your adapter.

like image 168
MH. Avatar answered Sep 28 '22 07:09

MH.


I just want to explain in little more detail answer of MH.
In your myArrayAdapter class in getView function you can assign your ID to the View (which actually means "row") like this:

public View getView(int position, View convertView, ViewGroup parent){

    View v = convertView;

    if (v == null) {
        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        v = inflater.inflate(mItemLayout, null);
    }

    String[] dataForOneRow = this.allRowsData.get(position);

    // Tag is expected to be an Object (Integer is an object)
    // our data are in String array - that's why we need to convert it into Integer
    // I assume here, your ID number is first item (No.0) in the array of data
    v.setTag(new Integer( Integer.valueOf(dataForOneRow[0]) ));

    /* 
    ...here you will set your data to display in your TextViews...
    */

    return v;
}

And then you need to know the ID of the row when (for example) user clicked on the row and some detailed Activity is going to start.

I have my ListView in the Fragment and this is the piece of code from my main Activity , from the declaration of Fragment , placed in the function onCreateView:

// here we assign "onClick listener" when user clicks a row
myListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Intent myRowClickIntent = new Intent(getActivity(), myDetailActivity.class);
        // we can send some data to the new Activity through "extras"
        // remember - our Tag is an object (Integer object) but putExtra() awaits some integer or string or some other type
        // so here we are saying that it should be understood/treated as an Integer
        myRowClickIntent.putExtra("item_id", (Integer)view.getTag() );
        startActivity(myRowClickIntent);
    }
});

And finally here is piece of code from onCreate method of my DetailActivity:

Bundle myExtras;
int myItemId;

myExtras = getIntent().getExtras();
if (myExtras != null) {
    myItemId = myExtras.getInteger("item_id");
}

Hope it helps somebody... :)
I'm also new to Android.
Big thank you to StackOverflow for such help in learning Android development :)

like image 40
Enriqe Avatar answered Sep 28 '22 05:09

Enriqe