Search code examples
androidlistlistadapterlayout-inflater

Android - Hiding List Items in a Custom Adapter crashing at .setText


I'm trying to hide a list item from my list using my custom list adapter. I can get the list item to hide, but then when I try to scroll the list, I can the following error:

 java.lang.NullPointerException: 
 Attempt to read from field 'android.widget.TextView com.example.QuestionListAdapter$ViewHolder.tvqid'
 on a null object reference
 at com.example.QuestionListAdapter.getView(QuestionListAdapter.java:196)

Here is my getView code:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    View rowView = convertView;
    Questions questionListItems = contactList.get(position);
    hidden = questionListItems.getHidden();

    if (rowView == null) {
        if (hidden.equals("true")){
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(R.layout.null_item, null);
            return rowView;
        } else {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(R.layout.activity_question_view_row, null);
            ViewHolder viewHolder = new ViewHolder();
            viewHolder.tvqname = (TextView) rowView.findViewById(R.id.name);
            viewHolder.tvqid = (TextView) rowView.findViewById(R.id.qid);
            rowView.setTag(viewHolder);
        }
    }

    final ViewHolder holder = (ViewHolder) rowView.getTag();
    holder.tvqid.setText(qid); //ERROR IS HERE
    holder.tvqname.setText(qname);
return rowview;     
} 

The Error is on the .setText as it's trying to set the text of a null item. But I've tried putting my hidden.equals("true") check over the the .setText but it still crashes the app.

I have also tried using the following code instead of the above, the below code removed the list items and made the list scrollable. But it had left a white space where those list items were.

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    View rowView = convertView;
    Questions questionListItems = contactList.get(position);
    hidden = questionListItems.getHidden();

    if (rowView == null) {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = inflater.inflate(R.layout.activity_question_view_row, null);
            ViewHolder viewHolder = new ViewHolder();
            viewHolder.tvqname = (TextView) rowView.findViewById(R.id.name);
            viewHolder.tvqid = (TextView) rowView.findViewById(R.id.qid);
            rowView.setTag(viewHolder);
    }

    final ViewHolder holder = (ViewHolder) rowView.getTag();
    holder.tvqid.setText(qid); //ERROR IS HERE
    holder.tvqname.setText(qname);

   if (hidden.equals("true")){
        rowView.setVisibility(View.GONE);
    } else {
        rowView.setVisibility(View.VISIBLE);

    }
  return rowview;     
} 

Also, in the 2nd code snippet above. I tried using rowView = new Space(this) instead of setting the visibility to GONE, but that crashed the app when scrolling.


Solution

  • I think you should work with the array you provide to your adapter and not the views of the adapter. Basically to hide an element you need to remove it from the Adapter's array. Nothing stops your from keeping a copy of the full array somewhere else (or in the adapter itself).

    For exemple, when you want to update your ListView you can do as follow, outside of your adapter, in the fragment / activity where you feed it your ArrayList of Questions :

    ArrayList<Questions> questionListItemsInAdapter = new ArrayList<>();
    
    for(Questions questions:questionListItems)
       if(!questions.getHidden())
          questionListItemsInAdapter.add(questions);
    
    adapter.bind(questionListItemsInAdapter);
    adapter.notifyDataSetChanged();