Android实现Spinner选中项联动RecyclerView加载对应分类数据
问题核心错误点
- 循环逻辑错误:
onItemSelected回调内构造列表的for循环写为for(int j=0;j<50;i++),循环自增的是外层回调参数i而非循环变量j,会直接触发死循环 - 刷新逻辑缺失:仅在回调中创建了新的Adapter实例,但没有将新实例绑定到RecyclerView,也没有触发数据集刷新通知,列表无法感知数据变化
- 细节错误:Toast仅创建实例未调用
show()方法,无法弹出提示;Spinner绑定的默认planets_array数据源和需求的4个分类不匹配
修复方案
前置配置
首先在res/values/arrays.xml中定义Spinner需要的4个分类选项:
<resources> <string-array name="category_array"> <item>Men</item> <item>Women</item> <item>Kids</item> <item>Cars</item> </string-array> </resources>
Adapter改造
给RecyclerView的Adapter新增数据集更新方法,复用同一个Adapter实例减少性能损耗:
public class ExampleAdapter extends RecyclerView.Adapter<ExampleAdapter.ExampleViewHolder> { private ArrayList<ExampleItem> mExampleList; public ExampleAdapter(ArrayList<ExampleItem> exampleList) { mExampleList = exampleList; } // 新增数据更新方法 public void setData(ArrayList<ExampleItem> newList) { mExampleList.clear(); mExampleList.addAll(newList); notifyDataSetChanged(); } // 下方保留你原有的ViewHolder、onCreateViewHolder、onBindViewHolder、getItemCount逻辑即可 public static class ExampleViewHolder extends RecyclerView.ViewHolder { // 你的item控件声明与绑定 public ExampleViewHolder(@NonNull View itemView) { super(itemView); } } @NonNull @Override public ExampleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.example_item, parent, false); return new ExampleViewHolder(v); } @Override public void onBindViewHolder(@NonNull ExampleViewHolder holder, int position) { ExampleItem currentItem = mExampleList.get(position); // 你的控件赋值逻辑 } @Override public int getItemCount() { return mExampleList.size(); } }
如果不想修改Adapter代码,每次切换分类时创建新Adapter实例后调用
mRecyclerView.setAdapter(mAdapter)也能实现刷新,但频繁创建Adapter实例性能较差,不推荐。
修复后的MainActivity代码
public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener { private RecyclerView mRecyclerView; private ExampleAdapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化Spinner Spinner spinner = findViewById(R.id.spinner); ArrayAdapter<CharSequence> spinnerAdapter = ArrayAdapter.createFromResource(this, R.array.category_array, android.R.layout.simple_spinner_item); spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(spinnerAdapter); spinner.setOnItemSelectedListener(this); // 初始化RecyclerView mRecyclerView = findViewById(R.id.recyclerView); mRecyclerView.setHasFixedSize(true); mLayoutManager = new LinearLayoutManager(this); mAdapter = new ExampleAdapter(new ArrayList<>()); mRecyclerView.setLayoutManager(mLayoutManager); mRecyclerView.setAdapter(mAdapter); // 默认加载第一个分类(Men)的数据,和Spinner默认选中项对齐 updateListByCategory(0); } @Override public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) { String selectedCategory = adapterView.getItemAtPosition(position).toString(); Toast.makeText(this, selectedCategory, Toast.LENGTH_SHORT).show(); updateListByCategory(position); } @Override public void onNothingSelected(AdapterView<?> adapterView) {} /** * 根据Spinner选中位置加载对应分类数据 * @param categoryPos 0:Men 1:Women 2:Kids 3:Cars */ private void updateListByCategory(int categoryPos) { ArrayList<ExampleItem> targetList = new ArrayList<>(); switch (categoryPos) { case 0: // 替换为男性姓名真实数据 String[] menNames = {"John", "Mike", "Tom", "Jack", "David"}; for (int i = 0; i < menNames.length; i++) { targetList.add(new ExampleItem(menNames[i], "男性用户" + (i+1))); } break; case 1: // 替换为女性姓名真实数据 String[] womenNames = {"Lily", "Lucy", "Amy", "Emma", "Olivia"}; for (int i = 0; i < womenNames.length; i++) { targetList.add(new ExampleItem(womenNames[i], "女性用户" + (i+1))); } break; case 2: // 替换为儿童姓名真实数据 String[] kidNames = {"Tim", "Bob", "Alice", "Zoe", "Max"}; for (int i = 0; i < kidNames.length; i++) { targetList.add(new ExampleItem(kidNames[i], "儿童用户" + (i+1))); } break; case 3: // 替换为车辆名称真实数据 String[] carNames = {"Tesla Model 3", "BYD Han", "BMW 3", "Benz C", "Audi A4"}; for (int i = 0; i < carNames.length; i++) { targetList.add(new ExampleItem(carNames[i], "车型" + (i+1))); } break; } mAdapter.setData(targetList); } }
注意事项
- 布局文件
activity_main中需要同时存在id为spinner的Spinner控件、id为recyclerView的RecyclerView控件,否则会触发空指针异常 - 示例中的分类测试数据可以替换为你自己的业务数据
- 声明Adapter变量时尽量使用具体类型而非基类
RecyclerView.Adapter,否则无法调用自定义的setData方法
内容的提问来源于stack exchange,提问作者Kazanaki HD
相关产品推荐
相关产品推荐

