1

I know it's duplicate question, but I didn't find proper answer. In my custom list-view having a two textview and one Editext, when I inserted a value in edit text and scroll then I loss value of edited text. And when I pass string value for an adapter through list adapter then it will show blank edit text.

Here my Adapter code:

class CreateAdapter extends ArrayAdapter<String> {
        String[] strItecode=null;
        String[] strItem;
        String[] strQuantity,text;
        Context context;
        int temp;
        CreateAdapter(Context context, String[] strItemcode, String[] strItem,
                String[] strQauntity) {
            super(context, R.layout.create_list_item, R.id.txtItemcode, strItemcode);
            this.context = context;
            this.strItecode = strItemcode;
            this.strItem = strItem;
            this.strQuantity = strQauntity;
            text= new String[strItem.length];
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            temp=position;
            LayoutInflater mInflater = (LayoutInflater) context
                    .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            if (convertView == null) {

                holder = new ViewHolder();
                convertView = mInflater
                        .inflate(R.layout.create_list_item, parent, false);

                holder.txtItecode = (TextView) convertView
                        .findViewById(R.id.txtItemcode);
                holder.txtItem = (TextView) convertView
                        .findViewById(R.id.txtItem);
                holder.editQuantity = (EditText) convertView
                        .findViewById(R.id.editcreateQuantity);
                holder.editQuantity.setTag(position);

                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
          holder.editQuantity.addTextChangedListener(new TextWatcher() {

              @Override
              public void onTextChanged(CharSequence s, int start,
                      int before, int count) {
                  text[temp] = s.toString();
              }

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

              }

              @Override
              public void afterTextChanged(Editable s) {

              }
          });
            holder.txtItecode.setText(strItecode[position]);
            holder.txtItem.setText(strItem[position]);
            holder.editQuantity.setText(text[temp]);

            return convertView;
        }

        class ViewHolder {
            TextView txtItecode;
            TextView txtItem;
            EditText editQuantity;
        }
    }

I'm working on it past 3 days, how I can fix this problem?

Alex Kulinkovich
  • 4,408
  • 15
  • 46
  • 50
Kuldeep
  • 367
  • 2
  • 7
  • 19
  • possible duplicate of [EditText loses content on scroll in ListView](http://stackoverflow.com/questions/8772714/edittext-loses-content-on-scroll-in-listview) – indivisible May 29 '14 at 19:07
  • And to extend on what that post says, if your list is small I would just use a ScrollView. – zgc7009 May 29 '14 at 19:11
  • use final `position` instead and remove `temp` – njzk2 May 29 '14 at 19:11
  • @zgc7009: why would you want to do that? scrollviews don't have the same capabilities, they just don't do the same thing. – njzk2 May 29 '14 at 19:12
  • 1
    @njzk2 sometimes you don't need the capabilities of a ListView, sometimes it is overkill. If you aren't going to be manipulating your list, and your list isn't very large, where is the benefit of a ListView? – zgc7009 May 29 '14 at 19:14
  • @njzk2 not working final position when i set final position then value inserted in many edit text – Kuldeep May 29 '14 at 19:21
  • did you got rid of `temp` altogether? – njzk2 May 29 '14 at 19:53
  • 1
    @zgc7009: Semantic is one benefit. You explicitly state that your content is a list. Good when someone else reads your code. Reusability is another. Simplicity, too. Capability to extend it in a breeze. Off course, when your content is not a list, there is no point (5 buttons on a home screen can look like a list, but they are not really) – njzk2 May 29 '14 at 19:53
  • @njzk2 I can agree with that, I have just also run into the issue where I had a small list of TextViews so thought I needed to use a ListView, but all I was really doing was adding code when I could have just dropped the few TextViews in a ScrollView and called it a day. – zgc7009 May 29 '14 at 19:59

1 Answers1

3

In addition to some of the comments about possibly using a ScrollView, the real issue with your code is how the ListView's Adapter is reusing the Views in conjunction with your TextWatcher(s).

Every single time a row needs to be displayed, the getView() method on that position will be called. The adapter can, and will, reuse the actual Views you've inflated in previous traversals to save memory.

That is usually a good thing, but is going to have consequences when you're working with EditTexts and TextWatchers.

First, holder.editQuantity.addTextChangeListener() is just going to keep adding a new TextWatcher on every layout pass. That's bad and is partly responsible for your issue.

Secondly, once a view is being reused, you're actually changing the text on it after setting the TextWatcher, which will trigger both the old (if there is one) and the new TextWatchers' onTextChanged() methods and change your stored values, which in turn is messing up your Views.

If you want to go the ListView/Adapter route with this, your solution will be to have a global TextWatcher variable, remove the TextWatcher from the View before setting the text in getView() (so that it doesn't fire its events when you don't want it to), and then re-adding it after you've set the text. However, since you can't keep creating new TextWatchers (as that will prevent you from removing the old ones as well as experience the same issue with messed up values), you'll also need a way to link to the appropriate position in your text[], since you won't be able to point to it from the getView() method. However, you can set the EditText's FocusChangeListener to determine when the View has focus (ie. it's being edited) and set the appropriate editing position from that)

E.g.

private int editingPosition = 0;
private TextWatcher watcher = new TextWatcher() {
          public void onTextChanged(CharSequence s, int start, int before, int count) {
              text[editingPosition] = s.toString();
          }
          public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
          public void afterTextChanged(Editable s) { }
      };

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

       // Before this is fine

      holder.editQuantity.removeTextChangedListener(watcher);

      holder.editQuantity.setText(text[temp]);

      holder.editQuantity.setOnFocusChangeListener(new OnFocusChangeListener() {       
          public void onFocusChange(View v, boolean hasFocus) {
            if(hasFocus) editingPosition = position;
          }
      });

      holder.editQuantity.addTextChangedListener(watcher);

      // The rest is good, just make sure to remove the call to setting the EditText's text at the end

      return convertView;
}
Cruceo
  • 6,763
  • 2
  • 31
  • 52
  • yes it's working fine but when i save value then only get focus-able list view value – Kuldeep May 30 '14 at 07:52
  • So its the same with onClickListeners and other created methods? if you create a new Object inside the getView() you will refresh it? – Thomas.L.T Sep 29 '17 at 07:53
  • Depends. `setOnClickListener` will override the previously set `View.OnClickListener`, whereas `addTextChangedListener` keeps adding new instances of the `TextWatcher`. – Cruceo Sep 29 '17 at 20:09