6

我正在尝试遵循 Android 最佳实践,因此在调试模式下我打开了以下所有功能:

StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build()); //detect and log all thread violations
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build()); //detect and log all virtual machine violations

当我尝试在主 (UI) 线程中使用任何类型的文件访问或 SQL 时,Android 现在对我大喊大叫。但我看到很多建议在主线程中使用文件访问和/或 SQL。例如,主要活动应该在内部加载默认偏好值onCreate(),以防它们尚未设置:

PreferenceManager.setDefaultValues(context, resId, readAgain);

糟糕——这会导致在第一次应用程序执行时访问文件,因为onCreate()在 UI 线程上调用。我能看到的唯一解决方法是启动一个单独的线程——它引入了一个与其他 UI 代码的竞争条件,这些代码可能会读取首选项并期望已经设置了默认值。

还要考虑诸如 DownloadManager 之类的服务。(实际上,它的 bug 太大了以至于在现实生活中毫无用处,但让我们假装它工作一秒钟。)如果您排队下载,您会收到一个事件(在主线程上),告诉您下载已完成。要实际获取有关该下载的信息(它只为您提供下载 ID),您必须查询 DownloadManager --- 这涉及一个光标,如果您打开了严格的策略,则会给您一个错误。

那么故事是什么——在主线程中访问游标可以吗?或者这是一件坏事,有一半的 Android 开发团队和 Android 书籍作者忘记了这一点?

4

1 回答 1

8

我能看到的唯一解决方法是启动一个单独的线程——它引入了一个与其他 UI 代码的竞争条件,这些代码可能会读取首选项并期望已经设置了默认值。

然后使用AsyncTask, 将setDefaultValues()调用doInBackground()和“可能读取首选项的其他 UI 代码”放入onPostExecute().

要实际获取有关该下载的信息(它只为您提供下载 ID),您必须查询 DownloadManager --- 这涉及一个光标,如果您打开了严格的策略,则会给您一个错误。

所以DownloadManager在后台线程中查询。

那么故事是什么——在主线程中访问游标可以吗?

这取决于你对“好”的定义。

在 Android 1.x 和大多数 2.x 设备上,使用的文件系统是 YAFFS2,它基本上序列化了所有进程中的所有磁盘访问。最终效果是,虽然您的代码在孤立的情况下可能看起来足够高效,但由于后台发生的其他事情(例如,下载新电子邮件),它有时在生产中显得迟缓。

虽然在 Android 3.x 及更高版本(他们切换到 ext4)中这不是一个问题,但毫无疑问,闪存 I/O 仍然相对较慢——它只会更慢一些,可以预见。

StrictMode旨在指出可能出现呆滞的地方。由您决定哪些是良性的,哪些不是。在一个理想的世界里,你会把它们都清理干净;在一个理想的世界里,我会有头发。

或者这是一件坏事,有一半的 Android 开发团队和 Android 书籍作者忘记了这一点?

这一直是一件“坏事”。

我不能代表“一半的 Android 开发团队”。我推测,在早期,他们希望开发人员应用他们现有的开发专业知识来检测迟缓行为——这与任何其他平台中的性能问题没有显着不同。Loader随着时间的推移,除了系统级别的更改(例如,YAFFS2->ext4)之外,他们一直在提供更多的模式来引导开发人员走上积极的道路(例如,框架),以减少这个问题。在某种程度上,他们正试图解决 Android 引入不同性能相关挑战的地方,例如单线程 UI。

同样,我不能代表所有 Android 图书作者。在我的书的早期版本中,我当然没有关注性能问题,因为我关注的是 Android 特性和功能。随着时间的推移,我在这些领域添加了更多建议。我还贡献了与这些主题相关的开源代码。2012 年,我将对我的书籍进行大量修改,并创建更多的开源项目,以继续解决这些问题。鉴于您的语气,我怀疑我(可能还有其他人)在您眼中在这方面完全失败,当然欢迎您发表意见。

于 2011-11-30T00:39:26.377 回答