Question

I was using SimpleCursorAdapter with an xml file with some views defined in it:

<LinearLayout ...>
    <ImageView android:id="@+id/listIcon" />
    <TextView android:id="@+id/listText" />
</LinearLayout>

My aim was to set the text color of the TextView, and the background color of the LinearLayout (that is, each row in the ListView) programmatically; the color is returned from a database.

I was getting NPEs when trying to manipulate the TextView for example, after it had found it with no complaints:

TextView tv = (TextView) findViewById(R.id.listText);
tv.setTextColor(color); // NPE on this line

Which is fair; if there's multiple entries in the list, it's reasonable to assume that "R.id.listText" will not work. So I extended SimpleCursor Adapter:

public View getView(int position, View convertView, ViewGroup parent) {
    View row = super.getView(position, convertView, parent);
    TextView text = (TextView) row.findViewById(R.id.listText);
    // ImageView icon = (ImageView) row.findViewById(R.id.listIcon);

    // If there's an icon defined
    if (mIcon_id != 0) {
        // icon.setImageResource(mIcon_id);
    }

    // If text color defined
    if (mTextColor != 0) {
        text.setTextColor(mTextColor);
    }

    // If background color set
    if (mBackgroundColor != 0) {
        row.setBackgroundColor(mBackgroundColor);
    }
    return(row);
}

And I get two different errors:

  • A similar NPE is thrown at "text.setTextColor(mTextColor)"
  • If the lines with the ImageView are uncommented, I get a "ClassCastException: android.widget.TextView" where I am calling "row.findViewById(R.id.listIcon)"

For reference, I was trying to use Commonsware's sample code, applying it to my situation. link (pdf)


Changed to this:

public View getView(int position, View convertView, ViewGroup parent) {
    convertView = super.getView(position, convertView, parent);

    if (convertView == null) convertView = View.inflate(mContext, R.layout.theme_item, null);
    TextView text = (TextView) convertView.findViewById(R.id.listText_tv);
    ImageView icon = (ImageView) convertView.findViewById(R.id.listIcon_iv);

    // If there's an icon defined
    if (mIcon_id != 0) {
        icon.setImageResource(mIcon_id);
    }

    // If text color defined
    if (mTextColor != 0) {
        text.setTextColor(mTextColor);
    }

    // If background color set
    if (mBackgroundColor != 0) {
        convertView.setBackgroundColor(mBackgroundColor);
    }
    bindView(convertView, mContext, mCursor);
    return(convertView);
}

Now I get a ClassCastException in the next activity (on list item click). Nothing has been modified in the next activity; it worked when using a SimpleListAdapter for the list which had entries (upon which clicking would lead to Activity2), so I think it's still something I'm doing wrong in the this extended class.

Was it helpful?

Solution

It's not true that convertView will always be an existing instance; you should check if it's null and then instantiate it. If not, you can change it just as you did.

This should be like:

public View getView(int position, View convertView, ViewGroup parent) {
    if(convertView == null)
        convertView = //inflate your row here
    View row = convertView;
    //Manipulate the row here
    return(row);
}

OTHER TIPS

I would modify the getView method:

public View getView(int position, View convertView, ViewGroup parent) {
    convertView = View.inflate(getContext(), R.layout.myLayout, null);
    TextView text = (TextView) convertView.findViewById(R.id.listText);
    ImageView icon = (ImageView) convertView.findViewById(R.id.listIcon);

    // If there's an icon defined
    if (mIcon_id != 0) {
      icon.setImageResource(mIcon_id);
    }

    // If text color defined
    if (mTextColor != 0) {
      text.setTextColor(mTextColor);
    }

    // If background color set
    if (mBackgroundColor != 0) {
      convertView.setBackgroundColor(mBackgroundColor);
    }

    return convertView;
}

I think that you're getting NPE because you're trying to create a textview and an imageview in a view where they aren't there.

When you want inflate a ListView with entries from a database, in your activity you define main.xml whith a ListView:

<LinearLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ListView 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:id="@+id/listView1">
</ListView>

and in the onCreate method you set the view to this xml with setContentView(R.layout.main);. Then you create your cursor to your database and your custom adapter:

    MySimpleCursorAdapter adapter = new MySimpleCursorAdapter(this, R.layout.entry,
                names, new String[] {Phones.NAME, Phones.NUMBER}, new int[] {
                R.id.listIcon, R.id.listText});
    startManagingCursor(cursor);
    ListView listView = (ListView) findViewById(R.id.listView1);
    listView.setAdapter(adapter);

and you define an entry.xml with your listIcon and listText, where the adapter points. In my example, I'm querying the names and numbers from contact list.

In your custom adapter, you should access to your textview and imageview inside getView or bindView without any problem.

Here you have and example to get all the contacts in your contact list with its picture, name and number, but using ListActivity instead of activity, and only one xml with two text views and an imageview. If you use ListActivity you don't need to use a ListView and you don't need to set the content view in the activity.

I hope it helps!

Don't forget to put : layout_width and layout_heigth for each of your views .

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top