Custom ArrayAdapter messing up views, with NullPointerException

129 views Asked by At

I am currently developing a content-creation application for Android. It´s main purpose is to let the user generate a list out of text and image entries (represented in the end by EditText and ImageView).

I hooked this list up to a ListView by writing a custom ArrayAdapter whilst using the ViewHolder Pattern

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

    // get current Entry
    Entry e = getItem(position);
    // variable for holding the view
    ViewHolder holder;

    // check if there is no view created
    if (convertView == null) {
        // prepare holder for view to be saved in
        holder = new ViewHolder();

        // get layout inflater
        LayoutInflater inflater = (LayoutInflater) super.getContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        // if current entry is an image entry
        if (e.getType().equals(Entry.Type.IMAGE_ENTRY)) {
            // inflate layout with ImageView
            convertView = inflater.inflate(R.layout.image_list_item,
                    parent, false);
            ImageView iView = (ImageView) convertView
                    .findViewById(R.id.imageDisplay);

            // save inflated view in holder
            holder.imageViewItem = iView;

            // store the holder with the view
            convertView.setTag(holder);

            // if it is a text entry
        } else if (e.getType().equals(Entry.Type.TEXT_ENTRY)) {
            // inflate layout with EditText
            convertView = inflater.inflate(R.layout.text_list_item, parent,
                    false);
            EditText tView = (EditText) convertView
                    .findViewById(R.id.textField);

            // save inflated view in holder
            holder.editTextItem = tView;

            // store the holder with the view
            convertView.setTag(holder);

        }
    } else {
        // get holder from existing view
        holder = (ViewHolder) convertView.getTag();
    }
    if (e != null) {
        if (e.getType().equals(Entry.Type.IMAGE_ENTRY)) {
            // load corresponding image
            holder.imageViewItem.setImageBitmap(((ImageEntry) e).getImage());
        } else if (e.getType().equals(Entry.Type.TEXT_ENTRY)) {
            // load corresponding text
            holder.editTextItem.setText(((TextEntry) e).getText());
        }
    }
    return convertView;
}

Contrary to tutorials and examples I´ve seen I need to distinguish between the layouts I inflate due to the difference between text and image entries. And this seems to be causing some trouble because sometimes after adding different entries after another I get these exceptions

E/AndroidRuntime(15812): java.lang.NullPointerException: Attempt to     invoke virtual method 'void android.widget.EditText.setText(java.lang.CharSequence)' on a null object reference 
E/AndroidRuntime(15812):    at <project>.util.EntryListAdapter.getView(EntryListAdapter.java:104)

So, it seems to me that the method gets called on the wrong view because otherwise there has to be an object of the type ‘EditText’. I´m not quite certain when the ListView triggers all its views to be redrawn and I´ve been experimenting with my adapter and list a lot but I can´t work out why it sometimes messes up the calls for my entries. Can anyone help me there?

2

There are 2 answers

1
Blackbelt On BEST ANSWER

if you don't override getViewTypeCount, you will get only one null convertView, so you will initialize it with image_list_item.xml or text_list_item.xml. If you want to handle differnt types of views override

 public int getViewTypeCount() {
       return 2;
 }

to handle two different types of view, and getItemViewType

public int getItemViewType (int position) {
    Entry e = getItem(position);
    if (e.getType().equals(Entry.Type.IMAGE_ENTRY)) {
        return 0;
    }
    return 1;
}

and in getView check for the return value of getItemViewType

1
prats110892 On

The ViewHolder pattern for ListView should be used when you know the view types of the positions before hand. If they are going to change dynamically when new positions are added (in essence if notifyDataSetChanged() is being called) then there are problems with the recycling.

For dynamically changing collections with different types of views it is better to use RecyclerView