【问题标题】:Synchronize access to Content Provider同步对 Content Provider 的访问
【发布时间】:2013-05-17 13:48:27
【问题描述】:

在我的应用程序中,我有一个 SyncAdapter,它使用 ContentProvider 将数据放入 SQLiteDatabase。几个月来一切都运行良好。在我添加了从 GCM 推送通知更新 ContentProvider 的第二种方法后,我开始收到一些用户的崩溃报告,例如

android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 3850)

android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 778)

以及其他几个与 sqlite 相关的例外情况。

虽然我听说 Sqlite 是同步的,我们不必担心,但我确实收到了这些错误,表明我需要以某种方式进行同步。有人处理过这个问题吗?

编辑: 这是一个示例堆栈跟踪

android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 778)
1   
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
2   
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:906)
3   
at android.database.sqlite.SQLiteSession.executeForLastInsertedRowId(SQLiteSession.java:788)
4   
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:86)
5   
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1469)
6   
at android.database.sqlite.SQLiteDatabase.insertOrThrow(SQLiteDatabase.java:1365)
7   
at com.makanstudios.conscious.provider.ConsciousProvider.doInsert(ConsciousProvider.java:225)
8   
at com.kaciula.utils.provider.BasicContentProvider.insert(BasicContentProvider.java:80)
9   
at android.content.ContentProvider$Transport.insert(ContentProvider.java:201)
10  
at android.content.ContentResolver.insert(ContentResolver.java:866)
11  
at com.makanstudios.conscious.net.DatabaseHandler.updateStatsCount(DatabaseHandler.java:351)
12  
at com.makanstudios.conscious.net.DatabaseHandler.updateStatsCount(DatabaseHandler.java:362)
13  
at com.makanstudios.conscious.gcm.GCMIntentService.onMessage(GCMIntentService.java:124)
14  
at com.google.android.gcm.GCMBaseIntentService.onHandleIntent(GCMBaseIntentService.java:223)
15  
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
16  
at android.os.Handler.dispatchMessage(Handler.java:99)
17  
at android.os.Looper.loop(Looper.java:137)
18  
at android.os.HandlerThread.run(HandlerThread.java:60)

还有另一个示例堆栈跟踪:

0   
android.database.sqlite.SQLiteException: not an error (code 0): Could not open the database in read/write mode.
1   
at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
2   
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:318)
3   
at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:229)
4   
at android.database.sqlite.SQLiteConnectionPool.openConnectionLocked(SQLiteConnectionPool.java:515)
5   
at android.database.sqlite.SQLiteConnectionPool.reconfigure(SQLiteConnectionPool.java:339)
6   
at android.database.sqlite.SQLiteDatabase.reopenReadWrite(SQLiteDatabase.java:832)
7   
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:213)
8   
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:164)
9   
at com.kaciula.utils.provider.BasicContentProvider.insert(BasicContentProvider.java:76)
10  
at android.content.ContentProvider$Transport.insert(ContentProvider.java:201)
11  
at android.content.ContentResolver.insert(ContentResolver.java:869)
12  
at com.makanstudios.conscious.net.DatabaseHandler.updateStatsCount(DatabaseHandler.java:351)
13  
at com.makanstudios.conscious.net.DatabaseHandler.updateStatsCount(DatabaseHandler.java:362)
14  
at com.makanstudios.conscious.gcm.GCMIntentService.onMessage(GCMIntentService.java:124)
15  
at com.google.android.gcm.GCMBaseIntentService.onHandleIntent(GCMBaseIntentService.java:223)
16  
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
17  
at android.os.Handler.dispatchMessage(Handler.java:99)
18  
at android.os.Looper.loop(Looper.java:137)
19  
at android.os.HandlerThread.run(HandlerThread.java:60)

【问题讨论】:

  • 如果您使用相同的SQLiteDatabase 对象/实例,所有访问都是同步的。因此,如果您使用相同的 SQLiteOpenHelper 对象/实例,则所有访问都是同步的。争用问题可能来自使用多个实例,或可能多个进程。
  • 我只使用一个实例。在我的 ContentProvider 的 onCreate() 中,我创建了 SQLiteOpenHelper 实例,并在我的所有提供者的方法中使用它来获取数据库。也许问题是在某些方法中我使用 getWritableDatabase() 和在某些 getReadableDatabase() 中,不知何故存在竞争条件。
  • 不要认为你有并发问题。在第二个错误的情况下,设备磁盘空间不足的可能性更大(对于 778)。不过,不确定第一个错误。你有堆栈跟踪吗?是什么方法导致的? INSERT 声明,对 getWritableDatabase() 的调用,还有什么?
  • 我添加了一种堆栈跟踪。当我收到推送通知并想在数据库中插入一些东西时,它总是发生在我的 GCMIntentService 中。堆栈跟踪有多种类型。
  • 你有没有解决这个问题?我也有类似的问题。

标签: android android-contentprovider


【解决方案1】:

只需在内容提供程序代码中使用一个 Helper。因此,始终将 1 个帮助程序连接到 1 个数据库,您不会有任何问题。

作为替代方案,如果您不提供对其他应用程序的访问权限,则无需使用内容提供程序。

在我决定改用 ORMLite 之前,我已经使用内容提供程序很长时间了。到目前为止,它在我所有的项目中都运行良好。不妨看看。

【讨论】:

  • 我在内容提供者中只使用了一个助手。而且我喜欢与内容提供者合作,因为我从使用它中获得了很多好处,并且 Android 人员推荐它并且所有谷歌应用程序都使用它。
  • 是的,按照我的标准很好:)
  • 您查看过记事本教程吗?我一直以这种方式使用代码,并且从未遇到过并发问题。
  • 最近没有。但我的内容提供商代码是基于去年的 Google I/O 应用程序。也许我在某处做错了什么。需要更多地研究它。谢谢。
  • DArkO,kaciula,Chris Martin 你能帮我解决stackoverflow.com/questions/26714771/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 2017-05-19
  • 2011-05-05
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多