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

使用for循环操作SharedPreferences存取值遇问题,求解决方案

搞定你的数据持久化问题:从SharedPreferences坑到正确选型

Hey,作为刚入门Android开发的新手,你踩的这些坑我当年也都踩过,慢慢来,咱们一步步理清楚。

先说说你用SharedPreferences的问题所在

你原来把StoreItem的每个字段拆分存储到SharedPreferences里,这种做法不仅繁琐,还很容易出问题:

  • 存储时先调用了editor2.apply(),之后又在循环后commit(),虽然这俩方法不冲突,但逻辑混乱,而且如果中途出现异常,可能导致部分数据没写入。
  • 读取时依赖Items Amount这个值,如果这个值没正确写入,整个循环就会出错,直接导致boughtItems为空或者数据不全。
  • 崩溃的直接原因是:数据读取失败后,imageName变成了默认的空格,调用getResourceID时找不到对应的drawable资源,抛出异常,进而在onResume调用showItems时崩溃。

修复SharedPreferences的正确姿势:用JSON序列化

别再拆分字段存储了,直接把整个ArrayList<StoreItem>转成JSON字符串存进去,简洁又不容易出错。你之前说Gson抛安全异常,大概率是Proguard混淆把StoreItem的字段名改了,导致Gson反射失败,加个混淆规则就行。

存储代码

// 存储boughtItems列表
SharedPreferences prefs = getSharedPreferences("BoughtStuff", MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
Gson gson = new Gson();
String itemsJson = gson.toJson(boughtItems);
editor.putString("saved_bought_items", itemsJson);
editor.apply(); // 用apply()异步写入,比commit()更高效

读取代码

// 读取boughtItems列表
SharedPreferences prefs = getSharedPreferences("BoughtStuff", MODE_PRIVATE);
String itemsJson = prefs.getString("saved_bought_items", "[]"); // 默认空数组
Gson gson = new Gson();
Type itemListType = new TypeToken<ArrayList<StoreItem>>() {}.getType();
boughtItems = gson.fromJson(itemsJson, itemListType);

// 保险起见,空判断避免NullPointerException
if (boughtItems == null) {
    boughtItems = new ArrayList<>();
}

解决Gson的安全异常

在你的Proguard规则文件(proguard-rules.pro)里加上:

# 不让Proguard混淆StoreItem类的字段
-keep class com.example.lorand.saimibutton.StoreItem { *; }

关于Parcelable:别用它做持久化!

你写的StoreArrayHolder其实用错场景了——Parcelable是用来在Activity、Fragment之间传递数据的,比如通过Intent传值,不是用来持久化到磁盘的。如果要让StoreItem支持Parcelable,正确写法应该是让它自己实现Parcelable接口:

public class StoreItem implements Parcelable {
    public int price;
    public String name;
    public String imageName;
    // 你的其他字段、构造方法和业务方法

    // Parcelable相关实现
    protected StoreItem(Parcel in) {
        price = in.readInt();
        name = in.readString();
        imageName = in.readString();
    }

    public static final Creator<StoreItem> CREATOR = new Creator<StoreItem>() {
        @Override
        public StoreItem createFromParcel(Parcel in) {
            return new StoreItem(in);
        }

        @Override
        public StoreItem[] newArray(int size) {
            return new StoreItem[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(price);
        dest.writeString(name);
        dest.writeString(imageName);
    }
}

如果要通过Intent传递这个列表:

// 发送方
Intent intent = new Intent(this, NextActivity.class);
intent.putParcelableArrayListExtra("bought_items", boughtItems);
startActivity(intent);

// 接收方
ArrayList<StoreItem> receivedItems = getIntent().getParcelableArrayListExtra("bought_items");

给新手的技术选型建议

根据你的场景,按优先级推荐:

  1. SharedPreferences + JSON:适合存储少量简单数据(比如你的商品列表,数量不多的话),代码简单,容易上手,是入门首选。
  2. Room数据库:如果以后你的商品数量变多,或者需要做查询、修改单个商品这类操作,Room是Android官方推荐的本地数据库方案,基于SQLite封装,API友好,还支持LiveData等组件,适合复杂数据持久化。
  3. Parcelable:只用来做组件间的数据传递,别用来存到本地磁盘。

最后,给你个小建议:在getResourceID方法里加个异常捕获,就算图片找不到也不会崩溃,而是显示默认图:

public int getResourceID(String resName, String resType, Context context) {
    try {
        return context.getResources().getIdentifier(resName, resType, context.getPackageName());
    } catch (Exception e) {
        e.printStackTrace();
        // 返回你的默认图片ID
        return R.drawable.default_item_image;
    }
}

内容的提问来源于stack exchange,提问作者Lorand D Nagy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:45:28