0

When records first appear on ListView, they seem fine and the getView if (convertView == null) is called correctly as records are visible for the first time.
However, if I scroll the ListView, even for the first time, if (convertView == null) is not called. Because of which the child in top item is repeated in the first item which appears on scroll. As per my understanding, if the ListView is scrolled for the first time, if (convertView == null) should be called.
Please correct me if I am wrong.
getView :

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

        try {
            ViewHolder holder = null;


            int rowType = getItemViewType(position);
            if (convertView == null) {


                holder = new ViewHolder();

                switch (rowType) {
                    case TYPE_ITEM:
                        convertView = inflater.inflate(R.layout.activity_item, null);

                        activityModel = (truegroups.model.Activity) arrActivity.get(position);

                        holder.activityLayout = (RelativeLayout) convertView.findViewById(R.id.activity_item_layout);
                        holder.startDate = (TextView) convertView.findViewById(R.id.lblStartDate);
                        holder.line = (TextView) convertView.findViewById(R.id.lblLine);
                        holder.endDate = (TextView) convertView.findViewById(R.id.lblEndDate);
                        holder.groupName = (TextView) convertView.findViewById(R.id.lblGroupName);
                        holder.activity = (TextView) convertView.findViewById(R.id.lblActivity);
                        holder.location = (TextView) convertView.findViewById(R.id.lblLocation);
                        holder.topInviteeLayout = (RelativeLayout) convertView.findViewById(R.id.invitationTopPanel);

                        int iCount = 0;
                        for (Invitation invitation : activityModel.getArrInvitations()) {

                            ImageView imgTopStatus = new ImageView(activity);

                            RelativeLayout.LayoutParams imgStatusParams = new RelativeLayout.LayoutParams(40, 40);
                            imgStatusParams.setMarginStart(160);
                            imgStatusParams.setMargins(160, 20, 0, 0);

                            if (iCount > 0)
                                imgStatusParams.addRule(RelativeLayout.BELOW, holder.arrImageStatus.get(iCount - 1).getId());

                            imgTopStatus.setId(iCount * iCount + iCount + 1);
                            holder.topInviteeLayout.addView(imgTopStatus, imgStatusParams);
                            holder.arrImageStatus.add(imgTopStatus);

                            TextView topInviteeName = new TextView(activity);

                            RelativeLayout.LayoutParams topInviteeParams = new RelativeLayout.LayoutParams(300, ViewGroup.LayoutParams.WRAP_CONTENT);
                            topInviteeParams.addRule(RelativeLayout.RIGHT_OF, imgTopStatus.getId());
                            if (iCount > 0)
                                topInviteeParams.addRule(RelativeLayout.BELOW, holder.arrlblTopInviteeName.get(iCount - 1).getId());


                            topInviteeParams.setMargins(15, 5, 5, 15);
                            topInviteeName.setTextColor(Color.BLACK);
                            topInviteeName.setTextSize(14);
                            topInviteeName.setBackgroundColor(Color.WHITE);
                            topInviteeName.setId(iCount * iCount + 2 * iCount + 2);
                            //topInviteeName.setText(invitation.getChildName());
                            holder.topInviteeLayout.addView(topInviteeName, topInviteeParams);
                            holder.arrlblTopInviteeName.add(topInviteeName);

                            //topInviteeParams.addRule(RelativeLayout.ALIGN_TOP, imgTopStatus.getId());
                           // imgStatusParams.addRule(RelativeLayout.ALIGN_BASELINE, topInviteeName.getId());

                            Button decline = new Button(activity);

                            RelativeLayout.LayoutParams paramsDecline = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 80);
                            paramsDecline.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
                            if (iCount > 0)
                                paramsDecline.addRule(RelativeLayout.BELOW, holder.arrDecline.get(iCount - 1).getId());

                            decline.setTextColor(Color.BLACK);
                            decline.setTextSize(9);
                            decline.setText("Decline");
                            decline.setId(iCount * iCount + 3 * iCount + 3);
                            holder.topInviteeLayout.addView(decline, paramsDecline);
                            holder.arrDecline.add(decline);

                            Button accept = new Button(activity);

                            RelativeLayout.LayoutParams paramsAccept = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, 80);

                            if (iCount > 0)
                                paramsAccept.addRule(RelativeLayout.BELOW, holder.arrAccept.get(iCount - 1).getId());
                            paramsAccept.addRule(RelativeLayout.RIGHT_OF, topInviteeName.getId());

                           // paramsAccept.addRule(RelativeLayout.ALIGN_BOTTOM, decline.getId());
                            paramsAccept.setMarginStart(155);

                            accept.setTextColor(Color.BLACK);
                            accept.setTextSize(9);
                            accept.setId(iCount * iCount + 8 * iCount + 8);
                            accept.setText("Accept");
                            holder.topInviteeLayout.addView(accept, paramsAccept);
                            holder.arrAccept.add(accept);

                            paramsDecline.addRule(RelativeLayout.ALIGN_TOP, accept.getId());

                            iCount++;
                        }

                        break;
                    case TYPE_SEPARATOR:
                        convertView = inflater.inflate(R.layout.activity_header, null);

                        holder.header = (TextView) convertView.findViewById(R.id.textSeparator);
                        holder.headerWeek = (TextView) convertView.findViewById(R.id.textWeekNumber);
                        break;
                }

                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }

            if (arrActivity.size() <= 0) {
                Log.d("Data", "No data found !!");

            } else {
                switch (rowType) {
                    case TYPE_ITEM:
                        activityModel = (truegroups.model.Activity) arrActivity.get(position);
//
                        holder.groupName.setText(activityModel.getGroupName());
                        holder.activity.setText(activityModel.getTitle());
                        holder.location.setText(activityModel.getLocation());
                        holder.startDate.setText(getHours(activityModel.getStartDate()));
                        holder.endDate.setText(getHours(activityModel.getEndDate()));



                        int iCount = 0;
                        for (Invitation invitation : activityModel.getArrInvitations()) {
                           ImageView imgStatus = holder.arrImageStatus.get(iCount);
                            //ImageView imgStatus = (ImageView) holder.topInviteeLayout.getChildAt(0);
                            if (invitation.getResponse().equals("3"))
                                imgStatus.setImageResource(R.drawable.notresponded);
                            else if (invitation.getResponse().equals("1"))
                                imgStatus.setImageResource(R.drawable.attending);
                            else
                                imgStatus.setImageResource(R.drawable.decline);

                           TextView inviteeName = holder.arrlblTopInviteeName.get(iCount);
                            //TextView inviteeName = (TextView) holder.topInviteeLayout.getChildAt(1);
                            inviteeName.setText(invitation.getChildName());

                            iCount++;
                        }


                        convertView.setOnClickListener(new OnItemClickListener(position));
                        break;
                    case TYPE_SEPARATOR:

                        holder.header.setText(getHeaderDate(String.valueOf(arrActivity.get(position))));

                        Calendar calendarGivenDate = Calendar.getInstance();
                        calendarGivenDate.set(Calendar.DAY_OF_MONTH, Integer.parseInt(String.valueOf(arrActivity.get(position)).split("/")[1]));
                        calendarGivenDate.set(Calendar.MONTH, Integer.parseInt(String.valueOf(arrActivity.get(position)).split("/")[0]));
                        calendarGivenDate.set(Calendar.YEAR, Integer.parseInt(String.valueOf(arrActivity.get(position)).split("/")[2]));

                        int weekNumber = calendarGivenDate.get(Calendar.WEEK_OF_YEAR);
                        holder.headerWeek.setText(StringUtils.join("WEEK ", String.valueOf(weekNumber)));

                        break;
                }

            }

            return convertView;
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(activity, e.getMessage(), Toast.LENGTH_LONG).show();
            Log.d("Exception : ", e.getMessage());
            return convertView;
        }
    }
Nitish
  • 13,845
  • 28
  • 135
  • 263
  • 1
    This isn't really related to your question, but when you put a `for` loop inside your `getView` code, you're potentially hurting performance quite a bit. Consider calculating the data from that for loop and storing it somewhere instead of computing it during scrolls. – Carl Anderson Jul 28 '15 at 21:24

1 Answers1

4

Because the ListView implements view recycling, you should never get a case where convertView == null after it is initialized.

When you intialize the ListView, it creates rows and calls getView on them until the screen is full of rows. Suppose this number is 10 rows, numbered 0-9, and the 10th row is only partially visible. When you scroll down, row 0 is scrolled out of view, and a new row needs to show up on the bottom. Instead of initializing a new block of memory for row 10, instead it takes row 0 and gives it to you in your getView() function. If you don't modify the values, it will show up once again on the bottom of the list, with all of the original values of row 0. In this example, the only time you'll get a null convertView, is if you're using multiple types of objects (like a separator), and the scrolling actually needs to create a new row before the previous row scrolls off the screen.

Thus you need to first create a row if the converView is null, but separately from that you need to (re)initialize all of the values inside the view afterwards.

The best strategy for writing a getView function follows this basic structure:

if (convertView == null) {
    convertView = new WhateverViewTypeYouNeed();
}

if (convertView != SEPARATOR) {
    initializeValues();
}
return convertView;

You can see this link for further reading.

Carl Anderson
  • 3,446
  • 1
  • 25
  • 45