【问题标题】:Android - SQLite ContentResolver insert/delete/update on UI Thread?Android - SQLite ContentResolver 在 UI 线程上插入/删除/更新?
【发布时间】:2014-10-27 09:34:43
【问题描述】:

我浏览了许多在 Android 中使用 SQLite 的示例/教程。假设您有一个使用 SQLite 的应用程序,ContentProviderCursorLoader、自定义 CursorAdapter。 现在,我发现的所有主要示例都依赖于CursorLoader 来获取数据到CursorAdapter,这在CursorLoader 的性质下以异步-UI 线程安全的方式发生。但是,这些相同的示例都通过主线程上的ContentResolver 进行插入/删除/更新调用(例如,来自onClickonResumeonPause)。 (Example) 他们不会将这些调用包装在AsyncTask 中,也不会启动单独的线程或使用AsyncQueryHandler。 为什么会这样,这么多写得很好的博客/例子怎么会犯这么明显的错误?还是简单的单行插入/删除/更新调用如此之快以至于它们足够安全以从主/ UI 线程启动?进行这些快速调用的正确方法是什么?

【问题讨论】:

  • 你的最后一句话可能是对的:查询操作肯定比单个插入/更新/删除复杂得多

标签: android sqlite sql-insert android-contentresolver ui-thread


【解决方案1】:

我也对在主线程上调用的示例感到困惑。我猜这些示例只是简化了演示,避免了额外的线程和回调,因为单个插入/更新/删除调用可能会很快返回。

除了用于查询的加载器模式之外,android 确实提供了一个辅助类 AsyncQueryHandler,从 API 级别 1 开始,用于支持完整 CRUD 回调的异步 CRUD 操作。 AsyncQueryHandler 在内部使用 HandlerThread 进行异步操作并将结果传递回主线程。

所以我确实认为 ContentProvider 查询应该在 UI 以外的工作线程中运行,根据官方设计,这些示例可能不是最佳实践。

=== 编辑

从官方框架文档中找到一个注解,见thisthis,第255行:

In practice, this should be done in an asynchronous thread instead of
on the main thread. For more discussion, see Loaders. If you are not
just reading data but modifying it, see {@link android.content.AsyncQueryHandler}.

=== 编辑 2 Link 包含上述引用的实际 android 开发指南

【讨论】:

  • 是的,我在我的问题中也提到了 AsyncQueryHandler ......我遇到的所有教程和示例仍然不能令人信服,只是因为它更简单并且不'甚至没有提到这不是你应该这样做的。对于一个正确的答案,我想要来自谷歌的官方(团队成员、文档、教程)或类似的东西(可能是一个受人尊敬的 GitHub 项目的链接,它以一种或另一种方式执行此操作),在主线程,或使用类似 AsyncQueryHandler...
  • 否则其他一切都只是我们对此的看法...... :)
  • @LeoK 有一个官方文档提到了这一点。请查看我的编辑。
  • 很酷,间接的,但基本上证实了我想知道的。谢谢。 (P.S. 我添加了一个指向实际文档的链接)
【解决方案2】:

这个问题想了很久。我想,这取决于我们尝试插入、更新或删除的文件的复杂性。如果我们的应用程序要插入或更新大文件,异步执行总是正确的,如果文件不会那么大,可以在 UI 线程上运行它。

但是,始终建议在单独的线程上继续执行数据库操作。

【讨论】:

  • 感谢您的回复。这并没有真正完全解释为什么解释最佳实践和其他方面的教程在插入/删除/更新的情况下正确/安全地做事从不打扰单独的线程。显然我还没有阅读所有好的教程,所以欢迎一些好的反例。 (尤其是来自 Google 或其他知名来源的)
【解决方案3】:

我想你已经回答了你自己的问题。我确实相信 CursorLoader 扩展了 AsyncTaskLoader。从 UI 线程进行的调用仅处理对 CusorLoader 的调用(它使用 AsyncTask。)调用所做的事情仍然不会在 UI 线程上发生。调用一个方法/函数,然后在单独的线程上运行,这仍然是远离 UI 线程的工作。

您认为 UI 线程上正在发生什么工作?

如果可能,请显示调试日志或您认为在 UI 上完成工作的示例。 不应该。

不想争论只是想知道你是如何得出 UI 工作的结论的?

【讨论】:

  • 你说得对,游标加载器是异步的。这是我自己在问题中写的。但是,插入/删除/更新调用是通过 ContentReslover 而不是 CursorLoader 进行的。如果对它的调用是在 UI 线程上进行的,那么通过 ContentReslover 的所有事情都在 UI 线程上完成。这很容易验证,只需将 Thread.sleep(5000) 添加到 ContentProvider 的插入覆盖的开头即可。如果你这样做,你会看到你的 UI 冻结 5 秒...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
  • 2010-11-02
  • 2012-10-29
  • 2014-09-07
  • 1970-01-01
  • 2014-12-28
相关资源
最近更新 更多