4

My activity contains a button and a ListView. The ListView contains a Spinner and an EditText view. I use the button each time I want to insert a new row entry in my Activity's ListView.

I have followed the instructions of previous stackoverflow threads like this one here: Android Listview with spinner and a checkbox on how to populate ListViews with focusable objects like Spinners.

My problem is that each time I dynamically add a new ListView entry in the ListView, the Spinner value of the previous ListView entry is lost (actuall the Spinner returns to its default setting). Say for simplicity that my Spinners are populated with the following data:

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

For example, if I select my first ListView's Spinner value to be "pear" and then I add a new ListView entry with my Button, the "pear" entry disappears from the 1st ListView Spinner 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 this one:

 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's 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 the following:

 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's 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;
}

 }
Community
  • 1
  • 1
goseib
  • 737
  • 3
  • 12
  • 24

1 Answers1

4

You're not handling the situation when getView gets a non-null convertView. In your example, after you add an item, ListView refreshes itself, and position that should display 'pear' gets an existing convertView (the one that was used previously to display 'apple') and you just pass it along to ListView without setting the data for current position. You cannot rely on ListView items to store any data, you should always set correct contents for position in getView method of your adapter. Just to be clear, I see that your code sets the selected position in the end of getView but the issue is that whatever is tagged to your convertView when it is passed to getView by recycler mechanism in ListView is random and can be associated with any position it used to display before.

To make your application work you'll have to create array of selectedItem values for all your spinners, and attach it as a member to your adapter. You'll have to update the corresponding value on each OnItemSelected event and you'll add a new value for each "add" button click. And when you prepare your view in getView you'll just set the selected spinners index to corresponding value in your array.

devmiles.com
  • 9,895
  • 5
  • 31
  • 47