2

我正在尝试在我的应用程序中使用与 WebService 进行事件同步的自定义日历。

一切都很好(嗯,不是真的)。

Calendar Activity 启动一个AsyncTask以便获取当前月份事件并将它们存储在数据库中,并且该onPostExecute方法更新视图以正确标记每一天。

我的问题是当用户进入日历活动然后快速回到主要活动几次时,比如说

Main Activity> Calendar Activity(按返回按​​钮)> Main Activity> Calendar Activity(按返回按​​钮)> ...

此时 Activity 由于 adatabase lock has not been available for 30 sec.或 App 因 a 而死机SQLiteConstraintException: error code 19

编辑SQLiteConstraintException行为不再发生

因为更新在我的应用程序中非常重要,所以每次我重新进入日历活动时,我都会删除数据库并用服务器新数据重新填充它,即使它是相同的,此时也是锁定的位置。

编辑

我已将Delete > Insert样式更改为: Update所有数据(设置flag列 = 0)>Insert新数据(设置flag列 = 1)> Delete(其中flag列 = 0)

我已经尝试过这个解决方案来取消AsyncTask活动完成但没有成功

我确信问题是我不完全理解我正在做的事情的过程,所以我错过了一些非常重要(或基本)的东西。

任何帮助改进我的代码或只是指出我正确的方向,将不胜感激。

提前致谢!

编辑

我的应用程序有一个负责Aplication创建单个数据库连接(getWriteableDatabase();MyApp.getDatabase();

4

2 回答 2

1

尝试序列化对您的数据库的访问。SQLiteDatabase 的每个实例都代表一个到 SQLite DB 的单独链接。在单个 SQLiteDatabase 实例上执行的操作是序列化的,但是当您在多个线程中处理多个 SQLiteDatabase 实例时,就会出现您描述的错误。

您没有发布任何代码,所以我只是假设您每次访问 AsyncTasks 中的数据库时都会获得一个新的 SQLiteDatabase 实例(使用 .getWriteableDatabase() / .getReadableDatabase())。尝试使用单个 SQLiteDatabase 实例并将其传递给任务。这样,您将序列化数据库访问并避免 AsyncTask 线程争夺数据库锁。

于 2012-11-19T18:14:15.937 回答
0

主要活动 > 日历活动(按返回按​​钮)> 主要活动 > 日历活动(按返回按​​钮)> ...

AsyncTask每次打开日历时,这可能会创建并开始一个新的。

AsyncTask如果您不明确取消它,每个仍然会运行。

这取决于您用来执行AsyncTask它们的 Android 版本/执行器,它们是并行运行还是序列化运行。>= Honeycomb 的默认行为是串行执行。在文档中的执行顺序部分进行了解释。AsyncTask

如果您使用串行 AsyncTask,您可以将几个(旧)任务排队,并且在执行最近的任务之前可能需要相当长的时间。离开活动时取消任务可能是个好主意。

您收到的database lock has not been available for 30 sec.警告表明您在一个线程中写入并尝试同时从另一个线程访问数据库。不确定这是否需要两个并行写入线程。

问题不在于使用不同的SQLiteDatabase实例。我认为如果你这样做,你会得到错误而不是警告,因为 Android 无法检查某些随机 SQLiteDatabase 对象是否在数据库上有写锁。

那么你能做什么:我假设你使用事务,因为在没有事务的情况下长时间锁定数据库几乎是不可能的。

  • 将事务的大小限制在一定数量,这样可以保证在其他线程之间使用数据库。
  • 使用动态停止事务db.yieldIfContendedSafely()。这将检查另一个线程是否想要访问数据库并暂时结束事务。缺点:它将提交更改,您无法回滚整个事务。
  • 按照预写日志文档中提到的SQLiteDatabase#enableWriteAheadLogging()&进行实验。beginTransactionNonExclusive()看起来它可以允许多线程访问而不会出现锁定问题。我还没有进一步调查这是否有效以及它有什么副作用。
于 2012-11-20T16:24:01.580 回答