Unconditional layout, inflation from view adapter: Should use View Holder pattern

Solution 1:

Try this

static class ViewHolder {

    private TextView friendsname;
    private ImageView thumb_image;
    private CheckBox cb;

}
public View getView(final int position, View convertView, ViewGroup parent) {

    ViewHolder mViewHolder = null;
    HashMap<String, String> song = null;

    if (convertView == null) {

        song = new HashMap <String, String>();
        mViewHolder = new ViewHolder();

        LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
        mViewHolder.friendsname = (TextView) convertView.findViewById(R.id.friendsName); // title
        mViewHolder.thumb_image = (ImageView) convertView.findViewById(R.id.list_image); // thumb image


        mViewHolder.cb = (CheckBox) convertView.findViewById(R.id.checkBox);

        convertView.setTag(mViewHolder);
        mViewHolder.cb.setTag(data.get(position));

        mViewHolder.cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean ischecked) {

                InviteFriends.isChecked[position] = buttonView.isChecked();

            }
        });

    } else {

        mViewHolder = (ViewHolder) convertView.getTag();

    }

    song = mViewHolder.cb.getTag();

    mViewHolder.friendsname.setText(song.get(InviteFriends.KEY_DISPLAY_NAME));
    mViewHolder.imageLoader.DisplayImage(song.get(InviteFriends.KEY_IMAGEPROFILE_URL), thumb_image);
    mViewHolder.cb.setChecked(InviteFriends.isChecked[position]);

    return convertView;
}

Solution 2:

you should init the convert view only if it is null

these lines

LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
// [...] the rest of initialization part
// [...] some changes that must be done at refresh
return convertView;

should look like this:

if (convertView == null) {
    LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
    // [...] the rest of initialization part
}
// [...] some changes that must be done at refresh
return convertView;

the goal is to recycle the already existing view in that list, not to init it each time you display it when scrolling the list for example.

Solution 3:

My suggestion is try to use convertView = vi.inflate(R.layout.activity_friend_list_row, null); insted of convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false); this may help you.

:- okey.. insted of accessing like this TextView friendsname = (TextView) convertView.findViewById(R.id.friendsName); // title ImageView thumb_image = (ImageView) convertView.findViewById(R.id.list_image); // thumb image you have to use viewholder class in your adapter

for example

static class ViewHolder {
    public TextView text;
    public ImageView image;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View rowView = convertView;
    // reuse views
    if (rowView == null) {
      LayoutInflater inflater = context.getLayoutInflater();
      rowView = inflater.inflate(R.layout.rowlayout, null);
      // configure view holder
      ViewHolder viewHolder = new ViewHolder();
      viewHolder.text = (TextView) rowView.findViewById(R.id.TextView01);
      viewHolder.image = (ImageView) rowView
          .findViewById(R.id.ImageView01);
      rowView.setTag(viewHolder);
    }

    // fill data
    ViewHolder holder = (ViewHolder) rowView.getTag();
    String s = names[position];
    holder.text.setText(s);
    if (s.startsWith("Windows7") || s.startsWith("iPhone")
        || s.startsWith("Solaris")) {
      holder.image.setImageResource(R.drawable.no);
    } else {
      holder.image.setImageResource(R.drawable.ok);
    }

    return rowView;
  }

Solution 4:

Unconditional layout inflation from view adapter: Should use View Holder pattern (use recycled view passed into this method as the second parameter) for smoother scrolling.

It means that you need to use View Holder pattern in your Adapter. The point of using View Holder is to reusing the views because inflating and using findViewById are slow.

When you're using the following code:

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

    ViewHolder mViewHolder;
    mViewHolder = new ViewHolder();
    LayoutInflater vi = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    convertView = vi.inflate(R.layout.activity_friend_list_row, parent, false);
    mViewHolder.cb = (CheckBox) convertView.findViewById(R.id.checkBox);
    convertView.setTag(mViewHolder);

    ...

    return convertView;

} 

you're not reusing the views but instead you always create new views.

You need to change your code to something like this (please check the comment):

// class for holding the cached view
static class ViewHolder {
   TextView tvFriendsName;
   ImageView imvThumbImage;
   CheckBox cbInviteFriend;
}

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

    // holder of the views to be reused.
    ViewHolder viewHolder;

    // get data based on the position
    HashMap<String, String> song = data.get(position);

    // if no previous views found
    if (convertView == null) {
       // create the container ViewHolder
       viewHolder = new ViewHolder();

       // inflate the views from layout for the new row
       LayoutInflater inflater = LayoutInflater.from(parent.getContext());
       convertView = inflater.inflate(R.layout.rowlayout, parent, false);

       // set the view to the ViewHolder.
       viewHolder.cbInviteFriend = convertView.findViewById(R.id.checkBox);
       viewHolder.tvFriendsName  = convertView.findViewById(R.id.friendsName);
       viewHolder.imvThumbImage = convertView.findViewById(R.id.list_image); 

       // save the viewHolder to be reused later.
       convertView.setTag(viewHolder);
    } else {
       // there is already ViewHolder, reuse it.
       viewHolder = (ViewHolder) convertView.getTag();
    }

    // now we can set populate the data via the ViewHolder into views
    viewHolder.tvFriendsName.setText(song.get(InviteFriends.KEY_DISPLAY_NAME));
    imageLoader.DisplayImage(song.get(InviteFriends.KEY_IMAGEPROFILE_URL), viewHolder.imvThumbImage);
    viewHolder.cbInviteFriend.isChecked(InviteFriends.isChecked[position]);

    return convertView;
}