Arindam Mukherjee
Arindam Mukherjee

Reputation: 2285

notifyDatasetChanged is not working inside the getView() method for Custom Adapter In Android

I am basically trying hide and show a text in the list row when I am clicking a button in the list row. I have added the onClick() for the button inside getView() method and then calling the notifyDataSetChanged(). But it is not working. No change in the text visibility. Here is my custom Adapter code:

  public class ListAdapter extends BaseAdapter {
    private Context context;
    private List<String> mListQuestion = null;
    private List<String> mListAnswer = null;
    ViewHolder holder = null;
    boolean flag = false;

    public ListAdapter(Context context, List<String> question, List<String> answer ) {
        this.mListQuestion = question;
        this.mListAnswer = answer;
        this.context = context;
    }

    @Override
    public Object getItem(int position)
    {
        return mListQuestion.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getCount() {
        return mListQuestion.size();
    }

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


        if (convertView == null)
        {
            LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = vi.inflate(R.layout.list_faq_item, null);

            holder = new ViewHolder();
            holder.tvQuestion = (TextView) convertView.findViewById(R.id.text);
            holder.tvAns = (TextView) convertView.findViewById(R.id.anstext);
            holder.ivArrow = (Button)convertView.findViewById(R.id.arrow_expand);
            convertView.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.tvQuestion.setText(mListQuestion.get(position));
        holder.tvAns.setText(mListAnswer.get(position));
        holder.ivArrow.setOnClickListener(new View.OnClickListener()
        {
                @Override
                public void onClick(View v)
                {
                    if (flag == false)
                    {
                        Logger.d("arrow clicked when flag is false");
                        holder.tvAns.setVisibility(View.VISIBLE);
                        holder.ivArrow.setBackgroundResource(R.drawable.up_arrow);
                        flag = true;
                    }
                    else if (flag == true)
                    {
                        Logger.d("arrow clicked when flag is true");
                        holder.tvAns.setVisibility(View.GONE);
                        holder.ivArrow.setBackgroundResource(R.drawable.down_arrow);
                        flag = false;
                    }
                    notifyDataSetChanged();
                }
        });

        return convertView;
    }


    static class ViewHolder {
        TextView tvQuestion;
        TextView tvAns;
        Button ivArrow;
    }

}

Can someone please tell what I am doing wrong here. Thanks in Advance.

-Arindam.

Upvotes: 1

Views: 2936

Answers (4)

HourGlass
HourGlass

Reputation: 1830

public class ListAdapter extends BaseAdapter {
    private Context context;
    private List<String> mListQuestion = null;
    private List<String> mListAnswer = null;
    ViewHolder holder = null;
    private List<Boolean> textViewVisibileState; 

    public ListAdapter(Context context, List<String> question, List<String> answer ) {
        this.mListQuestion = question;
        this.mListAnswer = answer;
        this.context = context;
        this.textViewVisibileState=new ArrayList<>(Arrays.asList(new Boolean[getCount()]));
          Collections.fill(this.textViewVisibileState,false);
    } 

    @Override 
    public Object getItem(int position)
    { 
        return mListQuestion.get(position);
    } 

    @Override 
    public long getItemId(int position) {
        return position;
    } 

    @Override 
    public int getCount() { 
        return mListQuestion.size();
    } 

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


        if (convertView == null)
        { 
            LayoutInflater vi = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = vi.inflate(R.layout.list_faq_item, null);

            holder = new ViewHolder();
            holder.tvQuestion = (TextView) convertView.findViewById(R.id.text);
            holder.tvAns = (TextView) convertView.findViewById(R.id.anstext);
            holder.ivArrow = (Button)convertView.findViewById(R.id.arrow_expand);
            convertView.setTag(holder);
        } 
        else 
        { 
            holder = (ViewHolder) convertView.getTag();
        } 

        holder.tvQuestion.setText(mListQuestion.get(position));
        holder.tvAns.setText(mListAnswer.get(position));
        if(textViewVisibileState.get(position))
{
            holder.tvAns.setVisibility(View.GONE);
                        holder.ivArrow.setBackgroundResource(R.drawable.down_arrow);

}
else
{
    Logger.d("arrow clicked when flag is false"); 
                        holder.tvAns.setVisibility(View.VISIBLE);
                        holder.ivArrow.setBackgroundResource(R.drawable.up_arrow);

}
        holder.ivArrow.setOnClickListener(new View.OnClickListener()
        { 
                @Override 
                public void onClick(View v)
                { 
                    if (textViewVisibileState.get(position))
                    { 
                        textViewVisibileState.set(position,false);
   } 
                    else
                    { 

                        textViewVisibileState.set(position,true);

 } 
                    notifyDataSetChanged();
                } 
        }); 

        return convertView;
    } 


    static class ViewHolder { 
        TextView tvQuestion;
        TextView tvAns;
        Button ivArrow;
    } 

} 

This will work.

Upvotes: 4

Karakuri
Karakuri

Reputation: 38585

Calling notifyDataSetChanged() causes ListView to rebuild everything. It will remove its child views, call getView() for all the items that are visible, and thus you will rebind all the data for those items.

But your data hasn't actually changed. You haven't modified anything in the questions list, so binding the data again is meaningless. Instead you have tried to change something in your ViewHolder object, but there's no guarantee that the convertView you get after a notifyDataSetChanged() is for the same position as before, so it's possible that some other item has been affected (or perhaps none at all?).

Try removing the call to notifyDataSetChanged() from the OnClickListener. A visibility change should cause a re-layout of the view hierarchy, but as long as you haven't told ListView that the data has changed, it should keep all its current children.

Upvotes: 1

The Original Android
The Original Android

Reputation: 6215

The variable flag is not context sensitive to object holder. So flag is always = false in your case. How about setVisibility(View.GONE) initially? And then setVisibility(View.VISIBLE) ONLY when ivArrow is clicked upon.

Upvotes: 1

life evader
life evader

Reputation: 988

Create an instance of the adapter, e.g Adapter myAdapter = new Adapter, set it to a listview or recyclerview e.g listview.setAdapter(mydapter) and everytime you add new data to it call adapter.notifyDataSetChanged()

Upvotes: 0

Related Questions