Question

I'm pretty new to Android, and I'm currently having some problem in using custom list adapter.

Basically, I want to make a list of question, with different type for each question (radio, checkbox, text, numeric). When the listview is generated, it displayed fine. But when I scroll down, the item from the top gets regenerated in the bottom.

My code is like this :

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

  View someView = convertView;

  //get question type
  String type = questions.get(position)[2];

  //declare viewholder
  final ViewHolder holder;
  Log.i("Position", Integer.toString(position));

  if (someView == null) {
    Log.i("convertView", "null");
    holder = new ViewHolder();

    LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    someView = inflater.inflate(R.layout.list_survey, parent, false);

    TextView textView = (TextView) someView.findViewById(R.id.surveyQuestion);
    textView.setText(questions.get(position)[1]);

    LinearLayout optionContainer = (LinearLayout) someView.findViewById(R.id.surveyOption);

    int size = options.get(position).size();

    //radio button
    if (type.equals("radio")) {

        RadioGroup group = new RadioGroup(this.context);
        RelativeLayout.LayoutParams groupParam = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        optionContainer.addView(group, groupParam);
        RadioButton radio = null;

        ArrayList<RadioButton> radios = new ArrayList<RadioButton>();

        for (int i=0; i<size; i++){
            radio = new RadioButton(this.context);
            radio.setId(i+1);
            radio.setText(options.get(position).get(i)[1]);
            group.addView(radio);
            radios.add(radio);
        }      
        group.setOnCheckedChangeListener(new OnCheckedChangeListener() 
        {
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                //Model element = (Model)group;
            }
        });

        holder.radiogroup = group;
        holder.radiobuttons = radios;

    //checkbox 
    } else if (type.equals("check")) {
        CheckBox checkbox = null;

        ArrayList<CheckBox> checks = new ArrayList<CheckBox>();

        for (int i=0; i<size; i++){
            checkbox = new CheckBox(this.context);
            checkbox.setId(i+1);
            checkbox.setText(options.get(position).get(i)[1]);
            optionContainer.addView(checkbox);
            checks.add(checkbox);
        }

        holder.checkboxes = checks;

    //textfield
    } else if (type.equals("txt")) {
        EditText field = null;

        ArrayList<EditText> fields = new ArrayList<EditText>();

        for (int i=0; i<size; i++){
            field = new EditText(this.context);
            field.setId(i+1);
            field.setHint(options.get(position).get(i)[1]);
            optionContainer.addView(field);
            fields.add(field);
        }

        holder.edittext = fields;
    //numeric
    } else if (type.equals("num")) {
        EditText field = null;

        ArrayList<EditText> fields = new ArrayList<EditText>();

        for (int i=0; i<size; i++){
            field = new EditText(this.context);
            field.setId(i+1);
            field.setHint(options.get(position).get(i)[1]);
            field.setInputType(InputType.TYPE_CLASS_NUMBER);
            optionContainer.addView(field);
            fields.add(field);
        }

        holder.edittext = fields;
    }

    someView.setTag(holder);

  } else {
    Log.i("convertView", "not null");
    holder = (ViewHolder) someView.getTag();
  }


    return someView;
}

The viewHolder class is here :

//viewHolder
static class ViewHolder {
    ArrayList<CheckBox> checkboxes;
    ArrayList<EditText> edittext;
    RadioGroup radiogroup;
    ArrayList<RadioButton> radiobuttons;    
}

What am I doing wrong?

I really appreciate your help. I've searched some other solutions but I can't get it work on my code.

Thanks

Was it helpful?

Solution

This happened because you are using the convertView and ViewHolder incorrectly. When you scroll down, the views will be recycled and the converView will not be null. The ViewHolder pattern is usually used this way:

public View getView(int position, View convertView, ViewGroup parent) {
    if(convertView == null) {
        inflate the view
        create a ViewHolder and store the necessary views in it
        use setTag to store the ViewHolder in the convertView
    }
    else {
        use getTag to get the ViewHolder
    }
    update the views // <- you are not doing this when convertView != null
}

The reason that convertView/ViewHolder pattern is used is that views in a list usually have the same layout but different data shown in them. In essence, the convertView (when not null) is a view that was previously used in the list and must be converted to show correct data for this position. By reusing it you avoid the expensive layout inflation. The ViewHolder is a further optimization with which you avoid the also expensive findViewById calls.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top