You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:48:52