2

I am currently adding TextViews inside a LinearLayout inside a ListView element using a for loop, because the amount of TextViews I have to add in there is variable. I am adding the items to the ListViews like you normally do. The problem is, when I scroll the items start to get more and more and when I scroll back up I end up with hundreds of items. I think it is because the ListView is reloading and cycling through the for loop once again and so adding every TextView multiple times. Can I stop that?

My code:

public class ListViewAdapter extends ArrayAdapter<RowItem> {

    private final Context context;

    public ListViewAdapter(Context context, List<RowItem> items) {
        super(context,  R.layout.list, items);
        this.context = context;
    }

    private class ViewHolder {
        TextView title;
        LinearLayout linearLayout;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        RowItem rowItem = getItem(position);

        LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.list_list, null);
            holder = new ViewHolder();
            holder.title = (TextView) convertView.findViewById(R.id.list_line);
            holder.linearLayout = (LinearLayout) convertView.findViewById(R.id.list_linear);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.title.setText(rowItem.getTitle());

            String data = rowItem.getData();
            String[] split0 = data.split("=");

            Log.e("DATA", data);
            Log.e("LINE", rowItem.getTitle());

            for (int j = 0; j < split0.length; j++) {
                String[] split1 = split0[j].split(":");

                LinearLayout parentLayout = new LinearLayout(MainActivity.context);
                parentLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
                parentLayout.setOrientation(LinearLayout.HORIZONTAL);

                for (int k = 0; k < split1.length; k++) {
                    TextView textView = new TextView(MainActivity.context);
                    textView.setText(split1[k]);
                    textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f));
                    textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
                    textView.setTextSize(18);

                    parentLayout.addView(textView);
                }
                holder.linearLayout.addView(parentLayout);
        }

        return convertView;
    }
}

My data sceme looks like this for one entry:

text1:text2=text3:text4

How it will look on the list:

text1    text2
text3    text4
Broadwell
  • 1,343
  • 2
  • 19
  • 33

1 Answers1

3

The problem is that the ArrayAdapter will call getView() each time the row becomes visible. If the row has been set up previously, it will pass in the previously set up View in the convertView parameter.

See here for details. From the documentation for convertView:

The old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using. If it is not possible to convert this view to display the correct data, this method can create a new view. Heterogeneous lists can specify their number of view types, so that this View is always of the right type (see getViewTypeCount() and getItemViewType(int)).

Edit: Since the original code proposed was causing problems, it looks like you might not be able to use the standard view holder design pattern after all. You have a unique set-up, where you are creating a dynamic amount of items in each row.

You might be able to do something that is slightly optimized, where you don't have to call inflate() on each getView() call, but still re-create the ViewHolder each time getView() is called, in order to populate the correct data when scrolling:

public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder holder;
    RowItem rowItem = getItem(position);

    LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

    if (convertView == null) {
        convertView = mInflater.inflate(R.layout.list_list, null);

    } 

    holder = new ViewHolder();
    holder.title = (TextView) convertView.findViewById(R.id.list_line);
    holder.linearLayout = (LinearLayout) convertView.findViewById(R.id.list_linear);
    convertView.setTag(holder);


    holder.title.setText(rowItem.getTitle());

        String data = rowItem.getData();
        String[] split0 = data.split("=");

        Log.e("DATA", data);
        Log.e("LINE", rowItem.getTitle());

        for (int j = 0; j < split0.length; j++) {
            String[] split1 = split0[j].split(":");

            LinearLayout parentLayout = new LinearLayout(MainActivity.context);
            parentLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
            parentLayout.setOrientation(LinearLayout.HORIZONTAL);

            for (int k = 0; k < split1.length; k++) {
                TextView textView = new TextView(MainActivity.context);
                textView.setText(split1[k]);
                textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f));
                textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
                textView.setTextSize(18);

                parentLayout.addView(textView);
            }
            holder.linearLayout.addView(parentLayout);
        }


    return convertView;
}

If that doesn't work, you could just go back to the basics, and just completely re-create the view on each call to getView():

public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        RowItem rowItem = getItem(position);

        LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

        //if (convertView == null) {
            convertView = mInflater.inflate(R.layout.list_list, null);
            holder = new ViewHolder();
            holder.title = (TextView) convertView.findViewById(R.id.list_line);
            holder.linearLayout = (LinearLayout) convertView.findViewById(R.id.list_linear);
            convertView.setTag(holder);

            holder.title.setText(rowItem.getTitle());

            String data = rowItem.getData();
            String[] split0 = data.split("=");

            Log.e("DATA", data);
            Log.e("LINE", rowItem.getTitle());

            for (int j = 0; j < split0.length; j++) {
                String[] split1 = split0[j].split(":");

                LinearLayout parentLayout = new LinearLayout(MainActivity.context);
                parentLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
                parentLayout.setOrientation(LinearLayout.HORIZONTAL);

                for (int k = 0; k < split1.length; k++) {
                    TextView textView = new TextView(MainActivity.context);
                    textView.setText(split1[k]);
                    textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f));
                    textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
                    textView.setTextSize(18);

                    parentLayout.addView(textView);
                }
                holder.linearLayout.addView(parentLayout);
            }     

        //} 

        return convertView;
    }
Community
  • 1
  • 1
Daniel Nugent
  • 43,104
  • 15
  • 109
  • 137
  • So now I have the problem that it doesn't take all my data to display. Let's say I have 10 entries to display in the listview, it only takes the data of the first 4 and displays it over and over again, till all 10 entries are displayed. The titles get displayed normally though. Basically it displays the first 4 entries over and over again, instead of one of each of the 10 – Broadwell May 23 '15 at 07:38
  • @Broadwell That's strange. It sounds like it might problem with your data source, whatever you pass into `List items` in this adapter. Try verifying that the List contains what you expect. If you can't get it sorted out post a new question and I'll take a look! – Daniel Nugent May 23 '15 at 08:05
  • I double checked the data and it contains everything I want. I also noticed convertView is no longer null after the first 4 lists. Anyway, here is the new question http://stackoverflow.com/questions/30410333/android-listview-only-using-first-entries – Broadwell May 23 '15 at 08:32
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/78604/discussion-between-daniel-nugent-and-broadwell). – Daniel Nugent May 23 '15 at 16:32
  • Yeah ok. How to do that? – Broadwell May 24 '15 at 09:08
  • Oh you added a link. derp – Broadwell May 24 '15 at 09:08