异步任务锁定数据库

时间:2012-11-19 16:37:21

标签: android sqlite android-asynctask

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

一切都很顺利(好吧,不是真的)。​​

日历活动启动AsyncTask以获取当前月份事件并将其存储在数据库中,onPostExecute方法更新视图以正确标记每一天。

我的问题出现在用户进入日历活动然后快速返回主要活动几次时,比方说吧

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

此时由于database lock has not been available for 30 sec.导致SQLiteConstraintException: error code 19或应用程序崩溃导致活动冻结{/ 1}}

  

编辑SQLiteConstraintException行为不再发生

由于在我的应用中更新非常重要,每次我重新输入日历活动时,我都会删除数据库,并使用服务器新数据重新填充它,即使是相同的,也是如此,并且在这一点上是锁定的地方。

  

编辑

     

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

我已尝试this解决方案取消活动结束时AsyncTask但未成功

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

任何有助于改进我的代码或只是指向正确方向的帮助都会非常感激。

提前致谢!

  

修改

     

我的应用程序有Aplication,负责创建单个数据库连接(getWriteableDatabase();),并且可以通过MyApp.getDatabase();方法访问此唯一连接。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

  

主要活动>日历活动(按后退按钮)>主要活动>日历活动(按后退按钮)> ...

这可能会创造&每次打开日历时都会开始一个新的AsyncTask

如果你没有明确地取消它,每个AsyncTask仍会运行。

如果它们并行或序列化运行,它取决于你用来执行AsyncTask的Android版本/执行程序。 > = Honeycomb的默认行为是串行执行。在AsyncTask documentation中的执行顺序部分进行了解释。

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

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

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

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

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