【问题标题】:Android - Updating listview based on spinner choice doesn't workAndroid - 基于微调器选择更新列表视图不起作用
【发布时间】:2017-09-08 19:27:25
【问题描述】:

虽然在 stackoverflow 上有很多与此主题相关的问题,但我可以说我已经查看了其中的许多问题并尝试了不同的方法,但仍然无法正常工作。

我有一个 ListView,我用我创建的自定义类的自定义适配器填充它。我还有一个微调器,我正在尝试将其用作列表的过滤器。

这是我的简化代码,我删除了所有不相关的内容,使其尽可能清晰,还简化了一些变量名称:

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);


    }

(Data.listByFilter() 是我在另一个类中创建的方法,它返回一个带有应用过滤器的 ArrayList)。

问题是当我点击微调器并选择一个项目时 - 什么也没有发生。

我曾尝试使用tourAdapter.clear(),然后使用add 命令添加项目,但这不起作用(对于微调器中的任何选择,ListView 都变为空)。

将项目添加到适配器就像项目被添加到 ListView 并在那里更新一样,但这不是我需要的,只是在我试图解决这个问题时起作用的东西。

谢谢。


编辑:

在尝试了很多事情之后,我终于找到了解决方案。虽然这似乎不是一个最佳解决方案,但由于我在每个微调器操作中都声明了一个新的TourAdapter,所以这是唯一对我有用的解决方案。 我所做的是声明一个新的TourAdapter,然后调用setAdapter。 另外,我将onNothingSelected 作为一个空方法。这就是它的样子(所有其他代码保持不变):

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) {
            }
        });

【问题讨论】:

标签: android listview spinner adapter android-adapter


【解决方案1】:

问题是您每次单击 Spinner 时都在创建一个新适配器(在 onItemSelected 和 onNothingSelected 方法中创建一个新的 TourAdapter(...)),并且此适配器未链接到您的列表。

在这两种方法中,您应该获取列表已有的适配器(使用 tourList.setAdapter 设置它),而不是创建一个新方法,在适配器上创建一个方法,在其上设置新元素并更新使用 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();

setNewElements 应该是适配器中的一个方法,如下所示:

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

***** 编辑 *****

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();

【讨论】:

  • 感谢您的评论。我的适配器没有任何“元素”变量。在我的适配器中,我使用 super 来调用超类构造函数。我在适配器中唯一更改的是 getView 方法(用于放大视图)。另外,你写的方法是无效的。但是,在tourAdapter = ((TourAdapter)) tourList.... 行中,您似乎将值分配给了tourAdapter。这似乎是一个问题,我应该如何从这里继续?
  • 另外,我尝试通过更改一点我的适配器(而不是执行分配)来实现此方法,但我得到一个IndexOutOfBoundsException,不确定这是否是正确的解决方案。
  • 您可以尝试将代码放在 onItemSelected 方法中我的第一个解决方案中的“编辑”下方吗?由于您使用 var toursData 作为数据源来填充列表,因此您需要使用新数据更新相同的引用并使用 notifyDataSetChanged() 更新列表
  • 我试过这样做,不幸的是它不起作用,我仍然得到IndexOutOfBoundsException。
  • 哈维尔瓦夫,感谢您的帮助。我不知何故想出了一个似乎不太理想的解决方案,但这是我唯一可以工作的解决方案。查看原始问题中的“编辑”部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多