Dear experts, I have been fighting for several hours now. The task is to dynamically generate a list using a custom adapter, check that the user has entered all the data into the dynamically created EditText fields, then checks the input correctness and, if everything is ok, then process the data further. The problem is that I validate the fields through a method in the main application class, getting the adapter a link to the static list of ArrayList objects.

Custom adapter looks like this:

// ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ списка с Π½ΡƒΠΆΠ½Ρ‹ΠΌ Ρ‚ΠΈΠΏΠΎΠΌ public static ArrayList<RowData> objects; 

Next standard is getting the list view, at this stage everything is great.

 @Override public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder holder; if (convertView == null) { holder = new ViewHolder(); LayoutInflater inflater = (LayoutInflater) ctx .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.row_data_send_for_adapter, parent, false); holder.editText = convertView.findViewById(R.id.send_new_counter); convertView.setTag(holder); }else { holder = (ViewHolder)convertView.getTag(); } holder.editText.setText(objects.get(position).getEditTextValue()); RowData p = getProduct(position); ((TextView) convertView.findViewById(R.id.place)).setText(getPlace(p.place)); ((TextView) convertView.findViewById(R.id.name_counter)).setText(getName(p.name_counter)); ((TextView) convertView.findViewById(R.id.old_counter)).setText(p.old_counter); // Initialize edit text to empty objects.get(position).setEditTextValue(holder.editText.getText().toString()); holder.editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { objects.get(position).setEditTextValue(holder.editText.getText().toString()); Log.d(Settings.getLog(), "position=" + position); // смотрим Π² ΠΊΠ°ΠΊΠΎΠΉ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΈ(Π² ΠΊΠ°ΠΊΠΎΠΌ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π΅ ΠΈΠ· списка) измСняСтся ΠΏΠΎΠ»Π΅ editText } @Override public void afterTextChanged(Editable editable) { } }); return convertView; } private class ViewHolder { protected EditText editText; } // собствСнно сам ΠΌΠ΅Ρ‚ΠΎΠ΄, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‰ΠΈΠΉ ссылку Π½Π° список ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² public ArrayList<RowData> getObjects(){ return objects; } 

Further in the main class, we declare a method that gets and iterates from the list. The remaining methods are omitted.

  private boolean checkField(){ boolean result = true; Log.d(Settings.getLog(), "object.length()=" + rowAdapter.getObjects().size()); for (RowData object : rowAdapter.getObjects()) { if (object.getEditTextValue().length() == 0) { Log.d(Settings.getLog(), "object.getEditTextValue().length()=" + object.getEditTextValue().length() + object.getClass().getName()); result = false; } Log.d(Settings.getLog(), "objects=" + object.getEditTextValue()); } Log.d(settings.getLog(), "result=" + result); return result; } 

And for some reason, validation is not correct, if the very first field from the list is filled with position 0. I set logs for a reason and decided to look at it. Suppose we have three items in the list. I click on the first EditText (should be position 0), but this is generated in the logs:

 2019-02-26 19:41:50.207 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=0 2019-02-26 19:41:50.207 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=1 2019-02-26 19:41:50.207 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=2 2019-02-26 19:41:50.207 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=0 2019-02-26 19:41:50.207 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=1 2019-02-26 19:41:50.207 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=2 2019-02-26 19:41:50.207 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=0 

So each time you change the text in EditText of the first element

If you change the text in any other element, then everything works out correctly.

 2019-02-26 19:44:39.415 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=1 

or

 2019-02-26 19:44:54.832 22933-22933/kz.kyzylzhar_su.kyzyljarsu D/myLog: position=2 

Help me understand what my mistake is.

  • Try to transfer the code from onTextChanged to afterTextChanged - YuriySPb ♦ pm
  • It will give nothing. There is no difference. Error somewhere else. - Gloster
  • You are not using the ViewHolder pattern correctly. All findViewById needs to be called once after the inflate, the same goes for adding handlers. Look at how many times getView is called with converView! = Null and how many times you addTextChangedListener to the same editText. - Yura Ivanov

1 answer 1

In general, after careful study and tests, I came to the conclusion that the views should have been created in any case without checking for null, after adjusting the code to the form

 @Override public View getView(int position, View convertView, ViewGroup parent) { final ViewHolder holder; holder = new ViewHolder(); LayoutInflater inflater = (LayoutInflater) ctx .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.row_data_send_for_adapter, parent, false); holder.editText = convertView.findViewById(R.id.send_new_counter); convertView.setTag(holder); RowData p = getProduct(position); ((TextView) convertView.findViewById(R.id.place)).setText(getPlace(p.place)); ((TextView) convertView.findViewById(R.id.name_counter)).setText(getName(p.name_counter)); ((TextView) convertView.findViewById(R.id.old_counter)).setText(p.old_counter); // Initialize edit text to empty objects.get(position).setEditTextValue(holder.editText.getText().toString()); holder.editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { objects.get(position).setEditTextValue(holder.editText.getText().toString()); // Log.d(Settings.getLog(), "position=" + position); } @Override public void afterTextChanged(Editable editable) { } }); return convertView; } 

everything worked fine. Maybe someone will be useful.