1

I have made a custom adapter based on the Baseadapter and a problem arises when I scroll the data in the list. The data gets all scrambled up. My guess is that my adapter keeps creating views but, I need one you of experts to take a look at my adapter code and point out the problem if you can my problem. I think I must have some problem with the getView() method.

public class ListViewAdapter extends BaseAdapter {
    public ArrayList<HashMap<String, String>> list;
    Activity activity;
    TextView txtFirst;
    TextView txtSecond;
    TextView txtThird;
    TextView txtFourth;
    TextView txtFifth;
    TextView txtSixth;
    TextView txtSeventh;
    TextView txtEighth;
    public ListViewAdapter(Activity activity,ArrayList<HashMap<String, String>> list){
        super();
        this.activity=activity;
        this.list=list;
    }
    @Override
    public int getCount() {
// TODO Auto-generated method stub
        return list.size();
    }
    @Override
    public Object getItem(int position) {
// TODO Auto-generated method stub
        return list.get(position);
    }
    @Override
    public long getItemId(int position) {
// TODO Auto-generated method stub
        return 0;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
        //LayoutInflater inflater=activity.getLayoutInflater();
        if(convertView == null){
            LayoutInflater inflater=activity.getLayoutInflater();
            convertView=inflater.inflate(R.layout.colmn_row, null);
            txtFirst=(TextView) convertView.findViewById(R.id.range);
            txtSecond=(TextView) convertView.findViewById(R.id.dropin);
            txtThird=(TextView) convertView.findViewById(R.id.dropmoa);
            txtFourth=(TextView) convertView.findViewById(R.id.windin);
            txtFifth=(TextView) convertView.findViewById(R.id.windmoa);
            txtSixth=(TextView) convertView.findViewById(R.id.velocity);
            txtSeventh=(TextView) convertView.findViewById(R.id.energy);
            txtEighth=(TextView) convertView.findViewById(R.id.time);
        }
        HashMap<String, String> map=list.get(position);
        txtFirst.setText(map.get(FIRST_COLUMN));
        txtSecond.setText(map.get(SECOND_COLUMN));
        txtThird.setText(map.get(THIRD_COLUMN));
        txtFourth.setText(map.get(FOURTH_COLUMN));
        txtFifth.setText(map.get(FIFTH_COLUMN));
        txtSixth.setText(map.get(SIXTH_COLUMN));
        txtSeventh.setText(map.get(SEVENTH_COLUMN));
        txtEighth.setText(map.get(EIGHTH_COLUMN));
        return convertView;
    }
}
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491

3 Answers3

3

First. You need to be using a ViewHolder Pattern. This would make code clean and efficient.

public class ListViewAdapter extends BaseAdapter {

    public ArrayList<HashMap<String, String>> list;
    Activity activity;

    public ListViewAdapter(Activity activity,ArrayList<HashMap<String, String>> list){
        super();
        this.activity=activity;
        this.list=list;
    }

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

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        //Only of the convertView is null, Inflate it.
        if(convertView == null){
            LayoutInflater inflater=activity.getLayoutInflater();
            convertView=inflater.inflate(R.layout.colmn_row, parent, false);

            holder = new ViewHolder();
            holder.txtFirst=(TextView) convertView.findViewById(R.id.range);
            holder.txtSecond=(TextView) convertView.findViewById(R.id.dropin);
            holder.txtThird=(TextView) convertView.findViewById(R.id.dropmoa);
            holder.txtFourth=(TextView) convertView.findViewById(R.id.windin);
            holder.txtFifth=(TextView) convertView.findViewById(R.id.windmoa);
            holder.txtSixth=(TextView) convertView.findViewById(R.id.velocity);
            holder.txtSeventh=(TextView) convertView.findViewById(R.id.energy);
            holder.txtEighth=(TextView) convertView.findViewById(R.id.time);
        //Add the holder as a tag to the convertView
         convertView.setTag(holder);
        } else {
          holder = (ViewHolder) convertView.getTag();
        }
        HashMap<String, String> map=list.get(position);
        holder.txtFirst.setText(map.get(FIRST_COLUMN));
        holder.txtSecond.setText(map.get(SECOND_COLUMN));
        holder.txtThird.setText(map.get(THIRD_COLUMN));
        holder.txtFourth.setText(map.get(FOURTH_COLUMN));
        holder.txtFifth.setText(map.get(FIFTH_COLUMN));
        holder.txtSixth.setText(map.get(SIXTH_COLUMN));
        holder.txtSeventh.setText(map.get(SEVENTH_COLUMN));
        holder.txtEighth.setText(map.get(EIGHTH_COLUMN));

        return convertView;
    }

    private class ViewHolder {
        TextView txtFirst;
        TextView txtSecond;
        TextView txtThird;
        TextView txtFourth;
        TextView txtFifth;
        TextView txtSixth;
        TextView txtSeventh;
        TextView txtEighth;
    }
}

The difference is that every view in the list has its own references to the txtviews in its tag. And only the first time the View is inflates they are referenced. This would reduce the number of findViewById calls and improve the performance.

ngoa
  • 720
  • 4
  • 14
0

There are a few issues you have. Your approach is terrible. First, you should at least use ViewHolder pattern techniques. The ViewHolder pattern is a pattern that can be used to increase the speed at which ListViws render data. The reason for this improvement is that the number of times the findViewById method is invoked is drastically reduced, existing views do not have to be garbage collected and new views do not have to be inflated. Lets try to rearrange your code.

public class ListViewAdapter extends BaseAdapter {

   private ArrayList<HashMap<String, String>> mList; // did this really have to be public?
   private Activity mActivity; // I changed to a more proper variable name

   public ListviewAdapter(Activity activity, ArrayList<HashMap<String, String>> list) {
      // super(); yes I commented out this line
      this.mActivity = activity;
      this.mList = list;
   } 

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

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

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

   @Override
   public View getView(int position, View convertView, ViewGroup parent) {
      View view = convertView;
      ViewHolder holder;
      if (Utils.checkIfNull(view)) {
         LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         view = inflater.inflate(R.layout.colmn_row, parent, false); //don't set to null here, better to set to false. Refer to google's official docs
         holder = new ViewHolder();

         holder.txtFirst=(TextView) convertView.findViewById(R.id.range);
         holder.txtSecond=(TextView) convertView.findViewById(R.id.dropin);
         holder.txtThird=(TextView) convertView.findViewById(R.id.dropmoa);
         holder.txtFourth=(TextView) convertView.findViewById(R.id.windin);
         holder.txtFifth=(TextView) convertView.findViewById(R.id.windmoa);
         holder.txtSixth=(TextView) convertView.findViewById(R.id.velocity);
         holder.txtSeventh=(TextView) convertView.findViewById(R.id.energy);
         holder.txtEighth=(TextView) convertView.findViewById(R.id.time);

         view.setTag(holder);

      } else {
         holder = (ViewHolder) view.getTag();
      }

      HashMap<String, String> map=list.get(position);
      holder.txtFirst.setText(map.get(FIRST_COLUMN));
      holder.txtSecond.setText(map.get(SECOND_COLUMN));
      holder.txtThird.setText(map.get(THIRD_COLUMN));
      holder.txtFourth.setText(map.get(FOURTH_COLUMN));
      holder.txtFifth.setText(map.get(FIFTH_COLUMN));
      holder.txtSixth.setText(map.get(SIXTH_COLUMN));
      holder.txtSeventh.setText(map.get(SEVENTH_COLUMN));
      holder.txtEighth.setText(map.get(EIGHTH_COLUMN));

      return view;
   }

   private static class ViewHolder {
      private TextView txtFirst, txtSecond, txtThird, txtFourth, txtFifth, txtSixth, txtSeventh, txtEighth;

   }
}

As a side note, if you want the checkIfNull method here it is

/**
 * Method is used to check null value for any object
 * 
 * @param objectToCheck
 * @return boolean
 */
public static <T> boolean checkIfNull(T objectToCheck) {
    return objectToCheck == null ? true : false;
}

This should do the trick for you. Cheers!

portfoliobuilder
  • 7,556
  • 14
  • 76
  • 136
0

For all those are still struggling with listview scrambled data, switch to recyclerview already. I had the same problem, I tried the following:

  1. Using View-Holder pattern.
  2. Holding references to individual view in map.

I came to find that this has something to do the height of listview, if you set it to "wrap_content", getview() has to be called to measure the height of children in the list. This causes awkward behavior for convertview.

My solution was to replace the implementation of listview completely and switch to recyclerview.

karan vs
  • 3,044
  • 4
  • 19
  • 26