Mickey
Mickey

Reputation: 1505

Android - Updating listview based on spinner choice doesn't work

While there are many questions relating to this subject here on stackoverflow, I can say I've looked through many of them and tried different things, but still I don't get it to work.

I have a ListView which I populate with a custom Adapter of custom classes I've created. I also have a spinner, which I'm trying to use as a filter for the list.

This is my simplified code, I removed everything that isn't relevant here make it clearer as possible, also simplifying some of the variable names:

public class OnlineNavActivity extends AppCompatActivity {

    private ListView tourList;
    private ArrayList<Tour> toursData;
    private Spinner filterSpinner;
    private TourAdapter tourAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tours_online);

        // Set up the spinner
        filterSpinner = (Spinner) findViewById(R.id.country_spinner);
        addItemsToSpinner();
        filterSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                String selectedCountry = (String) parent.getItemAtPosition(position);
                Log.i(LOG_TAG, selectedCountry);
                if (!selectedCountry.equals(Data.ALL_COUNTRIES)) {  // if string does not equal to "All Countries"
                    toursData = Data.listByFilter(selectedCountry);
                }
                else {
                    toursData = Data.dataList;
                }
                tourAdapter = new TourAdapter(getApplicationContext(), toursData);
                tourAdapter.notifyDataSetChanged();
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
                toursData = Data.dataList;
                tourAdapter = new TourAdapter(getApplicationContext(), toursData);
                tourAdapter.notifyDataSetChanged();
            }
        });

        // Assign all of the data to the array at first, will change by filter spinner
        toursData = Data.dataList;

        // Generate the list view
        tourList = (ListView) findViewById(R.id.online_nav_list);
        tourAdapter = new TourAdapter(this ,toursData);
        tourList.setAdapter(tourAdapter);


    }

(The Data.listByFilter() is the method I've created in a different class which returns an ArrayList with the applied filter).

The problem is that when I click on the spinner and select an item - nothing happenes.

I have tried to use tourAdapter.clear() and then adding the items with add command but that didn't work (The ListView became empty for any selection in the spinner).

Adding items to the adapter worked as items were added to the ListView and updated there, but this is not what I need, just something that worked while I was trying to figure this out.

Thanks.


Edit:

After trying many things, I finally find a solution. While it doesn't seem like an optimal solution, since I declare a new TourAdapter on every spinner action, this is the only one that worked for me. What I did, is declaring a new TourAdapter and then calling setAdapter. Also, I have left onNothingSelected as an empty method. This is what it looks like (all the other code remains the same):

filterSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                String selectedCountry = (String) parent.getItemAtPosition(position);
                Log.i(LOG_TAG, selectedCountry);
                if (!selectedCountry.equals(Data.ALL_COUNTRIES)) {  // if string does not equal to "All Countries"
                    toursData = Data.listByFilter(selectedCountry);
                    Log.i(LOG_TAG, "first country is" + toursData.get(0).getCountry());
                }
                else {
                    toursData = Data.dataList;
                }
                tourAdapter = new TourAdapter(getApplicationContext() ,toursData);
                tourList.setAdapter(tourAdapter);
                //tourAdapter.notifyDataSetChanged();
            }

            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        });

Upvotes: 0

Views: 222

Answers (1)

Javier Varela
Javier Varela

Reputation: 11

The problem is you are creating a new adapter (new TourAdapter(...) within onItemSelected and onNothingSelected methods) every time you click on the Spinner and this adapter is not linked to your list.

In this two methods, instead of creating a new one, you should get the adapter the list already has (you set it with tourList.setAdapter), create a method on the adapter that set the new elements on it and update the list with notifyDataSetChange.

String selectedCountry = (String) parent.getItemAtPosition(position);
Log.i(LOG_TAG, selectedCountry);
if (!selectedCountry.equals(Data.ALL_COUNTRIES)) {
    toursData = Data.listByFilter(selectedCountry);
} else {
    toursData = Data.dataList;
}
tourAdapter = ((TourAdapter) tourList.getAdapter()).setNewElements(toursData);
tourAdapter.notifyDataSetChanged();

The setNewElements should be a method in the adapter like this:

public void setNewElements(List<Tour> newElementsList) {
    this.myElements = newElementsList;
}

***** Edit *****

String selectedCountry = (String) parent.getItemAtPosition(position);
Log.i(LOG_TAG, selectedCountry);
toursData.clear();
if (!selectedCountry.equals(Data.ALL_COUNTRIES)) {
    toursData.addAll(Data.listByFilter(selectedCountry));
}
else {
    toursData.addAll(Data.dataList);
}
tourAdapter.notifyDataSetChanged();

Upvotes: 1

Related Questions