1

我们有一个奇怪的错误。如果电池耗尽,我们的应用程序将丢失其数据(存储在 SQLite 中),但如果我们强行终止应用程序然后电池耗尽,则不会。

我们不确定是什么原因造成的。

编辑1:

丢失数据意味着什么?

  1. 当用户注册时,我们保存他的用户名等。
  2. 当应用程序关闭,强制关闭并且用户再次打开应用程序时,用户名就在那里
  3. 当电池耗尽并且应用程序在前台运行时。电池充电后,用户再次打开应用程序,用户名消失了。

对象如何存储:


 public Void perform(SQLiteDatabase db) {
                final ConfigEntry entry = new ConfigEntry(property, value);

                if(contains(property)) {
                    db.update(ConfigEntry.TABLE_NAME, databaseAdapter.convertToContentValues(entry), ConfigEntry.COLUMN_NAME + " = ?", new String[] { property });
                } else {
                    db.insertOrThrow(ConfigEntry.TABLE_NAME, null, databaseAdapter.convertToContentValues(entry));
                }
                return null;
            }
        });

所以基本上 db.insertOrThrow 被调用。

这是我们初始化数据库的方式:


public  S doInTransaction(TransactionTask task) {
        DatabaseHelper mDbHelper = DatabaseHelper.getInstance(mContext);
        SQLiteDatabase mDb = mDbHelper.getWritableDatabase();
        mDb.setLockingEnabled(true);
        mDb.beginTransaction();
        try {
            S result = task.perform(mDb);
            mDb.setTransactionSuccessful();
            return result;
        } finally {
            mDb.endTransaction();
        }
    }

4

3 回答 3

1

问题是您正在使用beginTransaction(). 如果您有电话 beginTransaction(),您需要拨打:

db.setTransactionSuccessful();
   } finally {
     db.endTransaction();
   }

下面或您的数据将不会被保存。原因在sqlite手册

中并且您的数据没有保存的原因是,如果您开始事务并且 db.setTransactionSuccessful();由于系统试图关闭它而没有被调用,那么数据将不会被保存。但是finally{}可能仍然会被调用,但这不会改变db.setTransactionSuccessful();未被调用的事实。

于 2013-01-16T22:43:16.893 回答
1

我不确定,但我希望我能提供一些问题或灵感来深入挖掘:

  1. 您是否监控过您的数据库是否完成了完整的初始创建过程,或者表是否存在但只有用户名丢失?您可以从设备上下载数据库文件并在您的 PC 上的 SQLite 工具中检查内容吗?

  2. 您在里面打开数据库,doInTransaction()但不在那里关闭它:

    public S doInTransaction(TransactionTask task) {
        DatabaseHelper mDbHelper = DatabaseHelper.getInstance(mContext);
        SQLiteDatabase mDb = mDbHelper.getWritableDatabase();
        //mDb.setLockingEnabled(true); // true is default, so it can be removed
        mDb.beginTransaction();
        S result = null;
        try {
            result = task.perform(mDb);
            mDb.setTransactionSuccessful();
        } finally {
            // rolls back if setTransactionSuccessful() wasn't called
            mDb.endTransaction();
            mDb.close();
        }
        return result;
    }
    
  3. 你完全确定你使用的是同一个数据库吗?我问是因为我曾经看到有人使用时间戳作为数据库名称的一部分。

  4. 您不是错误地创建了内存数据库吗?

  5. 设备因电池电量不足而死机有多种不同的方式:它可能只是死机,或者它实际上设法紧急关闭。哪一个是这样的?您是否有任何日志记录可以提供您的应用程序关闭时的一些内部信息?

总结一下:我怀疑原因在于您提供的代码,正如您所提到的,代码仅在按下按钮时执行。这将上述问题留待进一步调查(当然,有些我可能错过了......)。

于 2013-01-16T23:24:11.190 回答
0

非常感谢大家的帮助,我们终于找到了答案。

我们正在使用用户密码加密我们的数据库,并使用设备的MAC 地址对密码进行加盐处理。

发生的情况是,有时当用户在启动后没电时,当我们的应用程序运行并且我们请求 MAC 地址时它失败了,因为它仍然被禁用的网卡或其他东西。在这种情况下,我们创建了一个新的盐,当尝试读取数据库时它会失败。

于 2013-01-17T16:01:02.293 回答