Reputation: 3665
I have the list of travelers with custom adapter what consist two EditText - edtFirstName and edtLastName. I want when user enters text save changes to List, and when next button click send this List to another activity.
My code:
public class TravellersAdapter extends BaseAdapter {
private List<Traveler> itemsList;
private LayoutInflater inflater;
private Activity context;
public TravellersAdapter(Activity context, List<Traveler> itemsList) {
super();
this.itemsList = itemsList;
this.context = context;
inflater = LayoutInflater.from(context);
}
public int getCount() { return itemsList.size(); }
public Object getItem(int i) { return itemsList.get(i); }
public View getView(final int position, View view, ViewGroup viewGroup) {
if (view == null) {
view = inflater.inflate(R.layout.traveller_item, null);
}
Traveler currentItem = (Traveler) getItem(position);
EditText firstNameView = (EditText) view.findViewById(R.id.edtFirstName);
firstNameView.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable editable) {
currentItem.setFirstName(editable.toString());
}
});
return view;
}
}
For exemple List itemsList consist 5 items. When I edit 2-4 element all ok, but when I edit first or last element edited value assigned to all element in List. In dubugger i saw that method afterTextChanged
calls 5 times with different values of position
.
How to fix it?
Upvotes: 1
Views: 2926
Reputation: 1054
Create one more EditText
in the screen that is invisible with name invivisbleEt
.
And do the following thing in the addTextChangedListener
firstNameView.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable editable) {
if(!firstNameView.isFocused())
currentItem.setFirstName(editable.toString());
}
});
Also add this code in the onCreate
method for ListView
object.
lv.setOnScrollListener(new AbsListView.OnScrollListener() {
//public boolean scrolling;
@Override
public void onScrollStateChanged(AbsListView absListView, int scrollState) {
invivisbleEt.requestFocus();
}
@Override
public void onScroll(AbsListView absListView, int i, int i1, int i2) {
}
});
Upvotes: 0
Reputation: 28418
The issue happens because views are reusable (that is by design in Android API). So eventually you may assign more than 1 text watcher to the same text view. And all of the assigned watchers are fired when text inside of the text view is changed.
A quick fix (and non-optimal if the list is really long, say, of 1000+ items) would be to have a map of Traweller -> TextWatcher
.
Then inside of getView() you can do this (pseudo-code):
TextWatcher
for this Traweller
TextWatcher
, put in the map and assign to EditText
TextWatcher
from the EditText
and remove from the mapTextWatcher
, put in the map and assign to EditText
Upvotes: 2
Reputation: 24012
in getView method, the parameter position gives the position of the newly created childView, not the clicked childView's position.
use this to get the correct position:
final int actual_position = myList.getPositionForView((View) v.getParent());
in onClick(View v);
of the onClickListener
of any View. In you case, you must implement onTextChangedListener for that EditText.
here:
myList is the ListView
v is the View you clicked, in this case the childView of the parent(myList).
Upvotes: 3