Android:将SQLCipher数据库数据加载到ListView报错求助
解决SQLCipher数据库数据显示到ListView的报错问题
嘿,我之前把SQLite换成SQLCipher时也碰到过一模一样的崩溃,咱们一步步来排查解决这个get field slot from row 0 col 1 failed的问题!
最核心的原因:数据库未正确解密
SQLCipher和原生SQLite最大的区别就是必须用密钥解密,要是没正确传入密钥,数据库里的内容都是乱码,Cursor读取字段时自然会报错。
解决步骤:
- 首先必须初始化SQLCipher库:在打开数据库前一定要调用
SQLiteDatabase.loadLibs(getApplicationContext()); - 打开数据库时正确传入密钥,两种方式任选其一:
方式一:打开时直接指定密钥
方式二:打开后设置密钥String dbPath = getDatabasePath("your_db_name.db").getPath(); SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbPath, "your_secure_key", null);
👉 注意:密钥别硬编码在代码里,建议用加密的SharedPreferences或者Android Keystore来存储!SQLiteDatabase db = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE); db.execSQL("PRAGMA key = '" + yourSecureKey + "';");
检查查询语句和Cursor使用细节
虽然之前SQLite正常,但迁移后可能因为列索引或字段名的问题导致读取失败:
- 别用硬编码的列索引(比如
getString(1)),改用列名获取索引,避免表结构变动时出错:// 推荐写法 int secretColIndex = cursor.getColumnIndex("secret"); String secret = cursor.getString(secretColIndex); - 读取Cursor前一定要先判断是否能移动到第一行,避免空指针或越界:
if (cursor != null && cursor.moveToFirst()) { do { // 读取数据的逻辑 } while (cursor.moveToNext()); } - 可以打印Cursor的列信息来排查:
这样能确认你要读取的列是否真的存在。Cursor cursor = db.rawQuery("SELECT * FROM secrets", null); Log.d("DB_DEBUG", "总列数:" + cursor.getColumnCount()); for (int i = 0; i < cursor.getColumnCount(); i++) { Log.d("DB_DEBUG", "列" + i + "名称:" + cursor.getColumnName(i)); }
数据库迁移时的加密操作错误
如果是从原有SQLite数据库直接换成SQLCipher,没正确加密原有数据的话,数据库会损坏:
- 正确的迁移加密步骤:
之后用新的加密数据库文件来操作。String oldDbPath = getDatabasePath("old_unencrypted.db").getPath(); String newEncryptedDbPath = getDatabasePath("new_encrypted.db").getPath(); // 打开未加密的旧数据库 SQLiteDatabase unencryptedDb = SQLiteDatabase.openDatabase(oldDbPath, null, SQLiteDatabase.OPEN_READWRITE); // 附加加密的新数据库并导出数据 unencryptedDb.execSQL("ATTACH DATABASE '" + newEncryptedDbPath + "' AS encrypted KEY 'your_key';"); unencryptedDb.execSQL("SELECT sqlcipher_export('encrypted');"); unencryptedDb.execSQL("DETACH DATABASE encrypted;"); // 关闭旧数据库 unencryptedDb.close();
最后检查Cursor的生命周期
确保你没有在Cursor关闭后还去读取数据,比如在onDestroy里关闭了Cursor,但Adapter还在使用它。建议用CursorLoader或者确保Adapter使用的Cursor是有效的。
内容的提问来源于stack exchange,提问作者Jamie Fish
相关产品推荐
相关产品推荐

