2

In an activity I have a CustomListAdapter that contains two EditText fields for each row in the CustomListAdapter. Currently, I have OnFocusChangeListeners that updates the values taken from the EditText, and saves them into a database. However, the last changed value never gets updated. All changed values are saved, but the last one doesn't get saved because the focus was never changed after it was modified. The user changes the last value, clicks "back", and the OnFocusChangeListener never gets called again; therefore, the last value doesn't get saved.

So I tried to use an AddOnTextChangedListener ... however, I can only update the first element in the CustomListAdapter. Not only that, whenever I update the first element, it propagates to all the rest of the elements in the CustomListAdapter, setting the values of the EditText of all other rows to the first EditText field's value. Whenever I change any other row, nothing happens. I saw that the TextChangeListener gets called for every position in the list adapter, even if the text was not changed.

Is there a way to add a listener to each EditText in the CustomListAdapter so that it updates each individual EditText element corresponding to the correct data[position] in the CustomListAdapter?

my app

Code snippet:

public class CustomListAdapter extends ArrayAdapter {
    ArrayList data;

    [...]

    class MyTextWatcher implements TextWatcher {
        private int position;

        public MyTextWatcher(int position) {
            this.position = position;
        }

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

        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {

        }

        public void afterTextChanged(Editable s) {
            arraymap.put(position, Double.valueOf(s.toString()));
        }
    }

    [...]

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

    final EditText editText1 = (EditText) convertView.findViewById(R.id.edit_text1);
    final EditText editText2 = (EditText) convertView.findViewById(R.id.edit_text2);

    editText1.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        public void onFocusChange(View v, boolean hasFocus) {
                    data[position].save();
                }
            }
        }
    });

    editText2.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        public void onFocusChange(View v, boolean hasFocus) {
                    data[position].save();
                }
            }
        }
    });

    [...]

    //----------------------ALSO TRIED----------------------------
    editText1.addTextChangedListener(new MyTextWatcher(position));

    [...]

    }
}
jameswoo
  • 386
  • 3
  • 12
  • 3
    Your first approach works.. but not fully. Why not just simply have a temporary list variable that stores all those values, and if ever the user decides to click "back", you can compare if any other changes were made. If true, update the values, then send to db. Less call to db. Just a thought though. Cheers! :D – AL. May 17 '16 at 06:36
  • 1
    @McAwesomville Hi, thank you for your response! I am working on the same code with jameswoo. We would like to implement your suggestion, but we don't know when to save the last value. `setOnFocusChangeListener` wouldn't be called for the last thing the user changes. The user would click their last field, change the value, then click back. How would we grab this last value? Thank you – SaiyanGirl May 17 '16 at 15:17
  • 1
    Hey @SaiyanGirl will try to come up with something once I get back to my machine. Will post an answer when I do. :D Let me know if you guys also came up with something. :) Cheers! – AL. May 18 '16 at 12:01

1 Answers1

2

Okay. So as per my comment, I suggested to simply create a variable that temporarily stores the values when they are changed, then just send it to your DB afterwards.

But as I see your code, you are trying to have this inside the your Adapter class, which I think complicates things. So I went and looked around on how to implement this in a much more simpler way.

You're Adapter class, presuming that this is being used by a ListView, you can actually iterate over the listview items and read the values of the EditTexts from the Activity where the ListView is by creating a simple function, like so:

private List<SampleObj> retrieveTexts() {
        List<SampleObj> sampleObjs = new ArrayList<>();
        for (int i = 0; i < lv.getCount(); i++) {
            View item = lv.getChildAt(i);
            EditText et1 = (EditText) item.findViewById(R.id.et1);
            EditText et2 = (EditText) item.findViewById(R.id.et2);

            SampleObj so = new SampleObj(et1.getText().toString(), et2.getText().toString());
            sampleObjs.add(so);
        }
        return sampleObjs;
    }

The SampleObj here is just a class I made as a sample. It's simply an object with two String values (referring to the two EditText in your listview item).

public class SampleObj {

    String text1;
    String text2;

    public SampleObj() {
    }

    public SampleObj(String text1, String text2) {
        this.text1 = text1;
        this.text2 = text2;
    }

    public void setText1(String text1) {
        this.text1 = text1;
    }

    public void setText2(String text2) {
        this.text2 = text2;
    }

    public String getText1() {
        return text1;
    }

    public String getText2() {
        return text2;
    }

    @Override
    public String toString() {
        return "SampleObject { text1 = " + text1 + ", text2 = " + text2 + "}";
    }
}

So calling retrieveTexts() will return a list of SampleObjs that has the values you need. I made a log on what I was able to do and this is it's result:

D/SAMPLE: [SampleObject { text1 = 50, text2 = 0}, SampleObject { text1 = 50, text2 = 0}, SampleObject { text1 = 50, text2 = 0}, SampleObject { text1 = 50, text2 = 0}]

It would always retrieve the current value of the EditTexts. What you do with the data collected is now up to you (send it to DB). Just call it whenever you need it. Cheers! :D

Here's a post I used as reference for this. :)

Community
  • 1
  • 1
AL.
  • 36,815
  • 10
  • 142
  • 281
  • How do you check for changes though? As you say, "I suggested to simply create a variable that temporarily stores the values when they are changed", I can't seem to find a way to temporarily store these values. – jameswoo May 19 '16 at 04:41
  • I suggested "simply have a temporary list variable that stores all those values". In the answer I provided, you no longer have to. You can just call the function when you need to retrieve all the current values. – AL. May 19 '16 at 04:50
  • Or is your desired behavior have to be for every change still? – AL. May 19 '16 at 04:51
  • Sorry, I actually used the adapter instead of the listview, that is why it wasn't working, your solution is correct! – jameswoo May 19 '16 at 04:55
  • 1
    No worries. :) Cheers! :D – AL. May 19 '16 at 04:57
  • Will not work. Your item will be null if the list is long, or list needs scrolling. List items not visible will return null in your solution. – Sukitha Udugamasooriya Nov 11 '16 at 02:46