如何在SharedPreferences中保存/加载Sectioned RecyclerView的<List<Object>>数据
我来帮你搞定这个带分组和复选框的购物清单实现,还要解决两个列表的持久化保存问题~
实现带分组的购物清单(未勾选/已勾选)+ 数据持久化
1. 完善你的分组类
先把你给出的不完整HeaderRecyclerViewSection补全,它需要处理分组标题、列表项的绑定,以及复选框的状态切换回调,方便后续移动item到对应分组:
public class HeaderRecyclerViewSection extends StatelessSection { private String title; public List<ShoppingItem> list; private OnItemCheckedListener checkedListener; // 定义回调接口,通知外部item状态变化 public interface OnItemCheckedListener { void onItemChecked(ShoppingItem item, boolean isChecked); } public HeaderRecyclerViewSection(String title, List<ShoppingItem> list, OnItemCheckedListener listener) { super(SectionParameters.builder() .itemResourceId(R.layout.item_shopping) // 你的列表项布局 .headerResourceId(R.layout.section_header) // 分组标题布局 .build()); this.title = title; this.list = list; this.checkedListener = listener; } @Override public int getContentItemsTotal() { return list.size(); } @Override public RecyclerView.ViewHolder getItemViewHolder(View view) { return new ItemViewHolder(view); } @Override public void onBindItemViewHolder(RecyclerView.ViewHolder holder, int position) { ItemViewHolder itemHolder = (ItemViewHolder) holder; ShoppingItem item = list.get(position); // 绑定数据到视图 itemHolder.tvName.setText(item.getName()); itemHolder.cbChecked.setChecked(item.isChecked()); // 处理复选框点击事件 itemHolder.cbChecked.setOnCheckedChangeListener((buttonView, isChecked) -> { item.setChecked(isChecked); // 通知外部处理分组移动 if (checkedListener != null) { checkedListener.onItemChecked(item, isChecked); } }); } @Override public RecyclerView.ViewHolder getHeaderViewHolder(View view) { return new HeaderViewHolder(view); } @Override public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder) { HeaderViewHolder headerHolder = (HeaderViewHolder) holder; headerHolder.tvTitle.setText(title); } // 内部ViewHolder类 static class HeaderViewHolder extends RecyclerView.ViewHolder { TextView tvTitle; public HeaderViewHolder(View itemView) { super(itemView); tvTitle = itemView.findViewById(R.id.tv_section_title); } } static class ItemViewHolder extends RecyclerView.ViewHolder { TextView tvName; CheckBox cbChecked; public ItemViewHolder(View itemView) { super(itemView); tvName = itemView.findViewById(R.id.tv_item_name); cbChecked = itemView.findViewById(R.id.cb_item_check); } } }
2. 主页面初始化SectionedRecyclerView
在你的Activity/Fragment中,创建两个分组(未勾选/已勾选),设置适配器,并处理item状态变化后的分组移动逻辑:
public class ShoppingListActivity extends AppCompatActivity { private SectionedRecyclerViewAdapter sectionAdapter; private List<ShoppingItem> uncheckedItems = new ArrayList<>(); private List<ShoppingItem> checkedItems = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_shopping_list); // 先加载本地保存的数据 loadSavedData(); // 创建两个分组 HeaderRecyclerViewSection uncheckedSection = new HeaderRecyclerViewSection( "未勾选商品", uncheckedItems, this::onItemChecked); HeaderRecyclerViewSection checkedSection = new HeaderRecyclerViewSection( "已勾选商品", checkedItems, this::onItemChecked); // 设置适配器 sectionAdapter = new SectionedRecyclerViewAdapter(); sectionAdapter.addSection(uncheckedSection); sectionAdapter.addSection(checkedSection); RecyclerView recyclerView = findViewById(R.id.recycler_view); recyclerView.setLayoutManager(new LinearLayoutManager(this)); recyclerView.setAdapter(sectionAdapter); } // 处理item勾选状态变化,移动到对应分组 private void onItemChecked(ShoppingItem item, boolean isChecked) { if (isChecked) { uncheckedItems.remove(item); checkedItems.add(item); } else { checkedItems.remove(item); uncheckedItems.add(item); } // 通知适配器更新UI sectionAdapter.notifyDataSetChanged(); // 保存最新数据到本地 saveDataToLocal(); } }
3. 数据持久化保存(核心需求)
这里推荐用SharedPreferences(适合小量数据),如果你的清单数据量大,可以改用Room数据库。首先让ShoppingItem实现序列化:
public class ShoppingItem implements Serializable { private String name; private boolean isChecked; public ShoppingItem(String name, boolean isChecked) { this.name = name; this.isChecked = isChecked; } // getter和setter public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isChecked() { return isChecked; } public void setChecked(boolean checked) { isChecked = checked; } }
然后实现保存和加载方法:
// 保存数据到SharedPreferences private void saveDataToLocal() { SharedPreferences sp = getSharedPreferences("ShoppingList", MODE_PRIVATE); SharedPreferences.Editor editor = sp.edit(); try { // 序列化未勾选列表 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(uncheckedItems); String uncheckedStr = Base64.encodeToString(bos.toByteArray(), Base64.DEFAULT); editor.putString("unchecked_items", uncheckedStr); // 序列化已勾选列表 bos.reset(); oos.writeObject(checkedItems); String checkedStr = Base64.encodeToString(bos.toByteArray(), Base64.DEFAULT); editor.putString("checked_items", checkedStr); editor.apply(); } catch (IOException e) { e.printStackTrace(); } } // 从SharedPreferences加载数据 private void loadSavedData() { SharedPreferences sp = getSharedPreferences("ShoppingList", MODE_PRIVATE); String uncheckedStr = sp.getString("unchecked_items", null); String checkedStr = sp.getString("checked_items", null); if (uncheckedStr != null) { try { ByteArrayInputStream bis = new ByteArrayInputStream(Base64.decode(uncheckedStr, Base64.DEFAULT)); ObjectInputStream ois = new ObjectInputStream(bis); uncheckedItems = (List<ShoppingItem>) ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } if (checkedStr != null) { try { ByteArrayInputStream bis = new ByteArrayInputStream(Base64.decode(checkedStr, Base64.DEFAULT)); ObjectInputStream ois = new ObjectInputStream(bis); checkedItems = (List<ShoppingItem>) ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } // 初始化空列表(防止null) if (uncheckedItems == null) uncheckedItems = new ArrayList<>(); if (checkedItems == null) checkedItems = new ArrayList<>(); }
4. 补充布局文件
- 分组标题布局
section_header.xml:
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/tv_section_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:textSize="18sp" android:textStyle="bold" android:background="#f5f5f5"/>
- 列表项布局
item_shopping.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp" android:orientation="horizontal" android:gravity="center_vertical"> <CheckBox android:id="@+id/cb_item_check" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="16dp"/> <TextView android:id="@+id/tv_item_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="16sp"/> </LinearLayout>
这样一套下来,你就能实现一个带分组、支持复选框状态切换,并且能持久化保存两个列表内容的购物清单啦~
内容的提问来源于stack exchange,提问作者wilrus
相关产品推荐
相关产品推荐

