如何用JSON在单个Shared Preferences键中存储多属性数据?
你之前用多个SharedPreferences键存数据确实会越搞越乱,换成JSON存单个键的思路完全正确,刚好能适配你联系人列表的增删改查需求,下面我给你一步步拆解具体怎么操作:
核心思路
把每个联系人的属性(姓名、电话、地址、图片路径等)封装成一个实体类,然后把所有联系人组成的列表转换成JSON数组字符串,最后把这个字符串存在SharedPreferences的单个键里。读取的时候反过来,把字符串解析回联系人列表就行。
具体实现步骤
1. 定义联系人实体类
先创建一个Contact类,把你需要的属性都放进去,注意图片别存二进制(会让JSON变超大),存本地路径就好:
public class Contact { private String id; // 唯一标识,用来快速定位联系人做增删改 private String name; private String phone; private String address; private String imagePath; // 比如从相册选的图片存在APP私有目录的路径 // 空构造方法(Gson解析需要) public Contact() {} // 带参构造方法 public Contact(String id, String name, String phone, String address, String imagePath) { this.id = id; this.name = name; this.phone = phone; this.address = address; this.imagePath = imagePath; } // 别忘了写所有属性的getter和setter方法 }
2. 用Gson做JSON序列化/反序列化
Android里最常用的JSON工具就是Gson,不用自己写复杂的解析逻辑。先在你的build.gradle(Module级别)里加依赖:
implementation 'com.google.code.gson:gson:2.10.1'
3. 封装SharedPreferences工具类
写个工具类专门处理联系人的保存和读取,避免重复代码:
import android.content.Context; import android.content.SharedPreferences; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; public class ContactPrefsHelper { private static final String PREF_FILE_NAME = "ContactStorage"; private static final String KEY_CONTACT_LIST = "all_contacts"; private final SharedPreferences prefs; private final Gson gson; public ContactPrefsHelper(Context context) { prefs = context.getSharedPreferences(PREF_FILE_NAME, Context.MODE_PRIVATE); gson = new Gson(); } // 保存整个联系人列表 public void saveContacts(List<Contact> contactList) { String jsonString = gson.toJson(contactList); prefs.edit().putString(KEY_CONTACT_LIST, jsonString).apply(); } // 读取联系人列表,为空时返回空列表 public List<Contact> getContacts() { String jsonString = prefs.getString(KEY_CONTACT_LIST, null); Type listType = new TypeToken<ArrayList<Contact>>() {}.getType(); return gson.fromJson(jsonString, listType) != null ? gson.fromJson(jsonString, listType) : new ArrayList<>(); } }
结合ListView实现增删改查
现在把工具类和你的ListView逻辑结合起来:
添加联系人
// 初始化工具类 ContactPrefsHelper helper = new ContactPrefsHelper(this); // 获取当前所有联系人 List<Contact> contacts = helper.getContacts(); // 生成唯一ID(用时间戳或者UUID都行) String newContactId = String.valueOf(System.currentTimeMillis()); // 创建新联系人 Contact newContact = new Contact(newContactId, "张三", "13800138000", "北京市朝阳区", "/storage/emulated/0/Android/data/com.your.app/files/avatar.jpg"); // 添加到列表并保存 contacts.add(newContact); helper.saveContacts(contacts); // 刷新ListView适配器 yourContactAdapter.notifyDataSetChanged();
删除联系人
String targetContactId = "1695000000000"; // 要删除的联系人ID List<Contact> contacts = helper.getContacts(); // 遍历找到目标联系人并移除 for (int i = 0; i < contacts.size(); i++) { if (contacts.get(i).getId().equals(targetContactId)) { contacts.remove(i); break; } } helper.saveContacts(contacts); yourContactAdapter.notifyDataSetChanged();
编辑联系人
String targetContactId = "1695000000000"; List<Contact> contacts = helper.getContacts(); // 找到目标联系人修改属性 for (Contact contact : contacts) { if (contact.getId().equals(targetContactId)) { contact.setName("李四"); contact.setPhone("13900139000"); break; } } helper.saveContacts(contacts); yourContactAdapter.notifyDataSetChanged();
ListView展示
把getContacts()拿到的列表传给你的自定义适配器,在getView()方法里绑定数据:比如显示姓名、电话,用Glide/Picasso根据imagePath加载图片就行。
注意事项
- 图片存储:绝对别把图片二进制数据存到JSON里,会让SharedPreferences的存储文件变得超大,容易触发存储上限(一般SharedPreferences建议单键值不超过1MB),存本地路径是最优解。
- 数据量限制:如果你的联系人数量超过几百条,建议换成Room数据库,SharedPreferences更适合小体量的数据存储;如果只是几十条,完全够用。
- 线程安全:如果是在子线程操作SharedPreferences,建议用
commit()代替apply()(不过apply()是异步的,主线程用也没问题)。
内容的提问来源于stack exchange,提问作者Woogear
相关产品推荐
相关产品推荐

