ListView EditTexts values are messed up when scrol

2019-02-21 07:17发布

问题:

As I mentioned in the title, the listview duplicates edittexts values for the children after i=10 in the for loop in my code.

public class ExerciseAdapter extends ArrayAdapter<ExerciseSet> {
    private ArrayList<ExerciseSet> mExercise;
    private LayoutInflater inflater;

    private List<String> texts = new ArrayList<String>();

    public ExerciseAdapter(Context context, int textViewResourceId, ArrayList<ExerciseSet> objects) {
        super(context, textViewResourceId, objects);
        mExercise = objects;
        inflater = (LayoutInflater) getContext().
                getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    @Override
    public int getItemViewType(int position) {
        if(mExercise.get(position).isSet() == false) return 0;
        else return 1;
    }

    @Override
    public int getViewTypeCount() {
        return 2; // two types of rows, exercise headers and bodies (sets)
    }


    public View getView(final int position, View convertView, ViewGroup parent){
        View view = convertView;
        final Holder holder;

        for(int i = 0; i < mExercise.size(); i++) {
            texts.add(String.valueOf(i));
        }

        if (getItemViewType(position) == 0) {

            if (view == null) {

                view = inflater.inflate(R.layout.item_exercise_header, null);
                holder = new Holder();


                holder.exerciseTitleView = (TextView) view.findViewById(R.id.tv_exercice_title);
                view.setTag(holder);

            } else {

                holder = (Holder) convertView.getTag();
            }
            ExerciseSet exercise = mExercise.get(position);

            if (exercise != null)
                holder.exerciseTitleView.setText(exercise.getExerciseTitle());


        } else {

            if (view == null) {
                view = inflater.inflate(R.layout.item_set, null);
                holder = new Holder();

                holder.setCounterView = (TextView) view.findViewById(R.id.tv_set_counter);

                holder.cbSet = (CheckBox) view.findViewById(R.id.cb_setdone);

                holder.repsCapt = (EditText) view.findViewById(R.id.et_reps_number);

                holder.repsCapt.setTag(position); 

                holder.repsCapt.setText(texts.get(position));

                //holder.weightCapt = (EditText) view.findViewById(R.id.et_weight_number);

                //db = new DatabaseHandler(this.getContext());

                //holder.weightCapt.setTag(position);
                view.setTag(holder);

            } else {

                holder = (Holder) convertView.getTag();

            }
            ExerciseSet exercise = mExercise.get(position);

            /*
             * edit texts
             */
            int tag_position=(Integer) holder.repsCapt.getTag();
            holder.repsCapt.setId(tag_position);

            holder.repsCapt.addTextChangedListener(new TextWatcher() {

                   @Override
                   public void onTextChanged(CharSequence s, int start, int before,
                           int count) {
                             final EditText repsText = (EditText) holder.repsCapt;

                             if(repsText.getText().toString().length()>0){
                                 texts.add(repsText.getText().toString());
                             }else{
                                 Toast.makeText(getContext(), "Please enter some value", Toast.LENGTH_SHORT).show();
                             }

                         }

                   @Override
                   public void beforeTextChanged(CharSequence s, int start, int count,
                           int after) {
                       // TODO Auto-generated method stub
                   }

                   @Override
                   public void afterTextChanged(Editable s) {

                   }

               });

            if (exercise != null) {
                holder.setCounterView.setText(String.valueOf(exercise.getSetId()));
            }


            /*
             * check boxes 
             */

            holder.cbSet.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton button, boolean isChecked) {

                    if(isChecked)
                        mExercise.get(position).setCbChecked(true);
                    else
                        mExercise.get(position).setCbChecked(false);
                }
            });

            holder.cbSet.setChecked(exercise.isCbChecked());

        }

        return view;
    }

    static class Holder {
        public EditText weightCapt;
        public EditText repsCapt;

        // header row items
        TextView exerciseTitleView;

        // body row item
        CheckBox cbSet;
        TextView setCounterView;
    }

}

I dont know why, please help..

Edit_1: I tried saving the values into an arraylist and retrieve them while the views are reused but it still gives me duplicated values while I scroll down.

Edit_2: If my question is unclear please let me know!

Edit_3: I placed holder.repsCapt.setText(texts.get(position)) inside the if (exercise != null) { condition and the values are not duplicated anymore. But still if I scroll down and up the values get messed up.

回答1:

Your problem is surely connected with item views being reused by the list.
So check your conditions and make sure that you provide alternative text in all cases.
Let's begin with item type==0 like this:

if (exercise != null)
                    holder.exerciseTitleView.setText(exercise.getExerciseTitle());

add

else
    holder.exerciseTitleView.setText("debugging: nothing to show");


Edit
The same is about type==1:
- holder.repsCapt.setText(texts.get(position)) is called only on freshly inflated view
- holder.setCounterView.setText(String.valueOf(exercise.getSetId())) only when excersise is not null

Edit2
Well, for DEBUG purposes try not to reuse views in getView() - always inflate right from the start.

If everything becomes OK (or you get some empty fields) then return to my initial recommendation in this post. I suspect this scenario

If problem persists than you should pay attention to correctly getting data according to position.



回答2:

I managed to solve my issue after some digging in google, here's the outcome:

@SuppressWarnings("unused")
@Override
public View getView(final int position, View convertView, ViewGroup arg2) {
    final Holder holder;
    convertView = null;
    if(getItemViewType(position) == 0) {
    if (convertView == null) {

        convertView = inflater.inflate(R.layout.item_exercise_header, null);
            holder = new Holder();
            holder.exerciseTitleView = (TextView)               convertView.findViewById(R.id.tv_exercice_title);
        convertView.setTag(holder);

        } else {

            holder = (Holder) convertView.getTag();
        }
        ExerciseSet exercise = exerciseList.get(position);

        if (exercise != null)
            holder.exerciseTitleView.setText(exercise.getExerciseTitle());

     }
     else if (getItemViewType(position) == 1) { 
     if (convertView == null) {
        holder = new Holder();

                convertView = inflater.inflate(R.layout.item_set, null);

                // reps e.t
                holder.repsCapt = (EditText) convertView
                        .findViewById(R.id.et_reps_number);

                holder.repsCapt.setTag(position);

                // weight e.t
                if(exerciseList.get(position).getExerSave()!=null) {
                    holder.repsCapt.setText(exerciseList.get(position).getExerSave().getReps());

                }
                // t.v
                holder.setCounterView = (TextView) convertView.findViewById(R.id.tv_set_counter);

                // c.b
                holder.cbSet = (CheckBox) convertView.findViewById(R.id.cb_setdone);

                convertView.setTag(holder);

            }else {
                holder = (Holder) convertView.getTag();
            }

            /*
             * text views
             */
            ExerciseSet exercise = exerciseList.get(position);

            if (exercise != null) {
                holder.setCounterView.setText(String.valueOf(exercise.getSetId()));
            }

            /* 
             * edit texts
             */
            int tag_position=(Integer) holder.repsCapt.getTag();

            holder.repsCapt.setId(tag_position);

            holder.repsCapt.addTextChangedListener(new TextWatcher() {

               @Override
               public void onTextChanged(CharSequence s, int start, int before,
                       int count) {
                   final int position2 = holder.repsCapt.getId();
                   final EditText repsText = (EditText) holder.repsCapt;
                   if(repsText.getText().toString().length()>0){
                       Save sv;

                       ExerciseSet es = exerciseList.get(position2);
                       if(es.getExerSave() != null)
                           sv = es.getExerSave();
                       else sv = new Save();

                       sv.setSet(position2);
                       sv.setReps(repsText.getText().toString());

                       es.setExerSave(sv);
                       exerciseList.set(position2,es);
                   }
               }

               @Override
               public void beforeTextChanged(CharSequence s, int start, int count,
                       int after) {

               }

               @Override
               public void afterTextChanged(Editable s) {

               }
            });

            /*
             * checkboxes
             */
            holder.cbSet.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton button, boolean isChecked) {

                    if(isChecked)
                        exerciseList.get(position).setCbChecked(true);
                    else
                        exerciseList.get(position).setCbChecked(false);
                }
            });

            holder.cbSet.setChecked(exercise.isCbChecked());    
        }
        return convertView;
    }