Android: Spinners in ListView lose their values ​​when I add dynamically new ListView entries

In my activity there is a button and ListView. The ListView contains a Spinner and an EditText view. I use the button every time I want to insert a new row entry into my ActivityView list.

I followed the instructions from previous stackoverflows like this one: Android Listview with spinner and a checkbox on how to populate ListViews with custom objects like Spinners.

My problem is that every time I dynamically add a new ListView entry to the ListView, the Spinner value of the previous ListView entry is lost (the Spinner action reverts to the default setting). Say for simplicity that my Spinners are filled with the following data:

String spinner_data[] = {"apple", "banana", "pear", "watermelon", "strawberry"}; 

For example, if I select my first ListView Spinner value for a “pear” and then add a new ListView record with my button, the “pear” entry disappears from the first ListView counter and the default value “apple” appears).

Any help is appreciated!

This is my activity:

 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); lv = (ListView) findViewById(R.id.lv); da = new DataAdapter(this, new ArrayList<RawData>()); lv.setAdapter(da); btn_new = (Button)findViewById(R.id.btn_new); btn_new.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub da.add(new RawData(this)); da.notifyDataSetChanged(); } }); } 

The RawData class is as follows:

  public class RawData { private int selected_position; private ArrayAdapter<CharSequence> adapter; public RawData(Context context) { adapter = ArrayAdapter.createFromResource(context, R.array.data, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); } public ArrayAdapter<CharSequence> getAdapter() { return adapter; } /** * get adapter item text from selected position * @return */ public String getText() { return (String) adapter.getItem(selected_position); } public int getSelected() { return selected_position; } public void setSelected(int selected) { this.selected_position = selected; } } 

The DataArrayAdapter is as follows:

  public class DataArrayAdapter extends ArrayAdapter<RawData> { private Activity myContext; //private final List<RawData> list; public DataArrayAdapter(Activity context, List<RawData> list) { super(context, R.layout.row_view, list); myContext = context; } static class ViewHolder { protected RawData data; protected Spinner spn; protected EditText edt; } @Override public View getView(int position, View convertView, ViewGroup parent) { View view = null; if ( convertView == null ) { LayoutInflater inflator = myContext.getLayoutInflater(); view = inflator.inflate(R.layout.row_view, null); final ViewHolder viewHolder = new ViewHolder(); viewHolder.edt = (EditText)view.findViewById(R.id.edt); viewHolder.data = new RawData(myContext); viewHolder.spn = (Spinner)view.findViewById(R.id.spn); viewHolder.spn.setAdapter(viewHolder.data.getAdapter()); viewHolder.spn.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2_position, long arg3) { // TODO Auto-generated method stub viewHolder.data.setSelected(arg2_position); } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); // Update the TextView to reflect what in the Spinner view.setTag(viewHolder); } else { view = convertView; } // This is what gets called every time the ListView refreshes ViewHolder holder = (ViewHolder) view.getTag(); holder.spn.setSelection(getItem(position).getSelected()); return view; } } 
+4
source share
1 answer

You are not handling a situation where getView gets a nonzero convertView . In your example, after adding the ListView element, it updates and the position displaying the “pear” gets the existing convertView (the one that was previously used to display “apple”), and you simply pass it to the ListView without setting data for the current position. You cannot rely on ListView elements to store any data; you must always set the correct content for the position in the getView method of your adapter. To be clear, I see that your code sets the selected position at the end of getView , but the problem is that everything that is marked by your converter when it is passed to getView the recycler mechanism in ListView is random and can be associated with any position, which she previously displayed.

In order to work with your application, you will need to create an array of selectedItem values ​​for all your spinners and attach them to a member of your adapter. You will need to update the corresponding value in each OnItemSelected event, and you will add a new value for each click of the Add button. And when you prepare your view in getView , you simply set the selected spinners index to the appropriate value in your array.

+4
source

Source: https://habr.com/ru/post/1394861/


All Articles