
本文介绍如何在 android 应用中持久化存储“一个键对应四个字符串值”的结构化数据,通过 sqlite 数据库实现安全读写、动态更新与跨启动保留,避免硬编码和文件 i/o 的维护风险。
本文介绍如何在 android 应用中持久化存储“一个键对应四个字符串值”的结构化数据,通过 sqlite 数据库实现安全读写、动态更新与跨启动保留,避免硬编码和文件 i/o 的维护风险。
在 Android 开发中,当需要为每个唯一键(如 key1、key2)持久保存一组关联的多个字符串值(如 value1–value4),且要求支持运行时修改、重启不丢失时,SQLite 数据库是最规范、可扩展、类型安全的解决方案。相比 SharedPreferences(仅适合扁平化的单值键值对)或原始文件读写(易出错、无事务、难维护),SQLite 提供结构化表设计、ACID 事务保障和高效查询能力。
✅ 推荐方案:自定义 SQLiteHelper 管理多字段键值表
我们创建一张表 data_entries,包含主键 id(自增)、唯一业务键 entry_key(如 "key1"),以及四个字符串字段 val1、val2、val3、val4:
// DataContract.java — 定义表结构契约
public class DataContract {
public static final String TABLE_NAME = "data_entries";
public static final String COLUMN_ID = "_id";
public static final String COLUMN_KEY = "entry_key";
public static final String COLUMN_VAL1 = "val1";
public static final String COLUMN_VAL2 = "val2";
public static final String COLUMN_VAL3 = "val3";
public static final String COLUMN_VAL4 = "val4";
private static final String CREATE_TABLE_SQL = "CREATE TABLE " + TABLE_NAME + "("
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ COLUMN_KEY + " TEXT UNIQUE NOT NULL, "
+ COLUMN_VAL1 + " TEXT, "
+ COLUMN_VAL2 + " TEXT, "
+ COLUMN_VAL3 + " TEXT, "
+ COLUMN_VAL4 + " TEXT)";
}// DatabaseHelper.java — 继承 SQLiteOpenHelper
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "multi_value_db.db";
private static final int DATABASE_VERSION = 1;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(DataContract.CREATE_TABLE_SQL);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + DataContract.TABLE_NAME);
onCreate(db);
}
// 插入或替换一条记录(按 entry_key 唯一约束)
public long insertOrUpdateEntry(String key, String v1, String v2, String v3, String v4) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(DataContract.COLUMN_KEY, key);
values.put(DataContract.COLUMN_VAL1, v1);
values.put(DataContract.COLUMN_VAL2, v2);
values.put(DataContract.COLUMN_VAL3, v3);
values.put(DataContract.COLUMN_VAL4, v4);
// 使用 INSERT OR REPLACE 实现“存在则更新,不存在则插入”
return db.insertWithOnConflict(
DataContract.TABLE_NAME,
null,
values,
SQLiteDatabase.CONFLICT_REPLACE
);
}
// 根据 key 查询单条记录
public DataEntry getEntryByKey(String key) {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(
DataContract.TABLE_NAME,
null,
DataContract.COLUMN_KEY + " = ?",
new String[]{key},
null, null, null
);
DataEntry entry = null;
if (cursor != null && cursor.moveToFirst()) {
entry = new DataEntry(
cursor.getString(cursor.getColumnIndexOrThrow(DataContract.COLUMN_KEY)),
cursor.getString(cursor.getColumnIndexOrThrow(DataContract.COLUMN_VAL1)),
cursor.getString(cursor.getColumnIndexOrThrow(DataContract.COLUMN_VAL2)),
cursor.getString(cursor.getColumnIndexOrThrow(DataContract.COLUMN_VAL3)),
cursor.getString(cursor.getColumnIndexOrThrow(DataContract.COLUMN_VAL4))
);
cursor.close();
}
return entry;
}
// 更新单个字段(例如只改 key1 的 val2)
public int updateSingleValue(String key, String columnName, String newValue) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(columnName, newValue);
return db.update(
DataContract.TABLE_NAME,
values,
DataContract.COLUMN_KEY + " = ?",
new String[]{key}
);
}
}
// 数据载体类(可选,提升可读性)
public class DataEntry {
public final String key, val1, val2, val3, val4;
public DataEntry(String key, String val1, String val2, String val3, String val4) {
this.key = key; this.val1 = val1; this.val2 = val2; this.val3 = val3; this.val4 = val4;
}
}? 在 Activity/Fragment 中使用示例
DatabaseHelper dbHelper = new DatabaseHelper(this);
// ✅ 写入第一条记录
dbHelper.insertOrUpdateEntry("key1", "A1", "B1", "C1", "D1");
// ✅ 读取并赋值给变量
DataEntry entry1 = dbHelper.getEntryByKey("key1");
if (entry1 != null) {
String var1 = entry1.val1; // "A1"
String var2 = entry1.val2; // "B1"
// ...
}
// ✅ 永久修改单个值(重启后仍生效)
dbHelper.updateSingleValue("key1", DataContract.COLUMN_VAL2, "NEW_B1");⚠️ 关键注意事项
- 线程安全:SQLiteOpenHelper 实例应在 Application 或单例中复用,避免多线程并发写入;如需高并发,请考虑 Room(推荐升级路径)或加同步锁。
- 唯一性保障:entry_key 字段设为 UNIQUE,确保 insertOrUpdateEntry() 不会意外插入重复键。
- 空值处理:String 字段允许为 NULL,读取时务必判空(cursor.getString(...) 返回 null 而非空字符串)。
- 升级兼容性:后续增加字段时,在 onUpgrade() 中使用 ALTER TABLE ADD COLUMN,避免全量重建丢数据。
- 替代进阶方案:若项目已引入 Jetpack,强烈建议迁移到 Room,它基于 SQLite 封装,提供编译时 SQL 校验、LiveData 支持和更简洁的 DAO 接口。
通过以上实现,你将获得一个健壮、可维护、符合 Android 最佳实践的多值持久化方案——数据真正“永久”驻留设备,重启无忧,修改即生效。










