52

我正在设计一个需要执行以下步骤的android应用程序:

  1. 用户按下按钮或以其他方式指示“同步数据”。
  2. 同步过程将使用 REST Web 服务将数据移入和移出服务器。
  3. 数据将本地存储在 sqlite 数据库中。
  4. 同步过程应向 UI 提供状态更新/消息
  5. 不应允许用户在同步过程中徘徊到应用程序的其他部分并做更多的工作。

第一次运行同步过程可能需要 10-20 分钟。初始同步后,传输和存储的数据将减少,我预计该过程需要 1-2 分钟或更短的时间。

我一直在阅读有关 androidAsyncTask和使用服务的各种示例的大量信息……但我并不完全理解选择一种设计而不是另一种设计的设计注意事项和权衡取舍。我目前使用 AsyncTask 将我的演示项目存根。观看(大部分)开发 Android REST 客户端应用程序后: http ://code.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html#我对此处描述的设计模式感到困惑感觉过于复杂,也许是因为我只是“不明白”。

我来自 java、spring、web 和桌面应用程序背景。在手持设备方面进行思考和设计对我来说是相当新鲜的。(更改屏幕布局时会发生什么?当我运行同步时电话响起会发生什么?)退后两步,如果初始同步将是一个如此漫长的运行过程,有没有更好的方法我要考虑问题->解决方案、用户体验、用户对手机上运行的应用程序的期望?

很想听听一些更有经验的安卓开发者的意见,他们已经在这些问题上苦苦挣扎。

4

5 回答 5

44

在我看来,这是主流/普通 Android 开发中最棘手/最困难的部分。例如,在黑莓上,这在 TIMES 上更容易。

绝对需要使用Service.

AsyncTask不适合,因为它Activity通过Context句柄与您紧密“绑定”(否则您将无法Activity从您的AsyncTask. 但是,一旦进入后台Activity,操作系统就可以杀死它。Activity进入后台的一个示例原因可能是来电 - 用户切换到电话应用程序,因此您Activity变得不可见。在这种情况下(取决于当前的 RAM 状态)操作系统可能会决定终止其中一个后台(用户不可见)活动。

一些开发人员通过安排一个静态的东西来解决这个问题,以便在其中进行长时间运行的操作。有些人建议使用Application实例。这是因为静态的东西Application存在,而整个应用程序进程存在。但是,这些都是不正确的解决方法。当操作系统决定是时候杀死 Android 中的进程也可能会被杀死。Android 操作系统对于它可以杀死什么以及以什么顺序有自己的考虑。所有进程都被划分为 5 个级别的“可杀性”。这是指定这些级别的文档。在那里阅读很有趣:

因为运行服务的进程的排名高于具有后台活动的进程,所以启动长时间运行操作的活动可能会更好地为该操作启动服务,而不是简单地产生一个线程——特别是如果该操作可能比活动。例如,在后台播放音乐并将相机拍摄的照片上传到网站。 使用服务可确保操作至少具有“服务进程”优先级,而不管活动发生什么。

Activity用户启动长时间运行的操作的位置应显示 a以ProgressDialog确保用户在操作运行时不执行任何其他操作。指南在这里

此外,如果您当前不可见,您很可能希望使用NotificationManager通知用户您的长时间运行的操作完成(或失败) 。Activity这是NotificationManager 信息开始的地方。

于 2010-11-14T11:57:22.437 回答
12

为了最好地决定如何处理您的情况,您必须权衡多种考虑因素。听起来您需要对这两种方法进行很好的比较......所以这里列出了在手持设备上工作时必须考虑的相似之处、不同之处和其他注意事项。

服务是您的应用程序的一部分,它没有 UI。它可以由要启动的 UI(Activity) 调用,也可以由应用程序的任何其他组件启动。开发时,您可以自由地将它放在不同的线程上,甚至可以在不同的任务或进程中运行它。这允许您最终将其与您的 UI 分开。此外,您可以根据需要启动服务以独立运行(startService)或将您的活动绑定到它(bindService)。通过使用自定义处理程序,您可以设置回调以根据您的进度更新 UI。如果用户更改活动,服务不一定会结束,但操作系统可能会随时结束。

AsyncTask 总是从 UI 线程实例化。它只允许特定的回调,但为了相对较短的事务(与专用的单独线程服务相比)简化了多线程的过程,这些事务与活动执行的操作固有地相关联。每当用户更改活动时,AsyncTask 就会被置于“暂停”状态,甚至可能因为您的活动不再有 UI 线程而死亡。

我最担心的事情是,如果应用程序第一次需要 10-20 分钟,我会假设用户会临时更改任务或将手机放下直到完成(这可能会导致所有如果手机处于休眠状态,也会出现同样的并发症)。考虑到这一点,绑定到您的活动的线程服务可能是您的最佳选择。为了保护你的 UI,我会为你的 Activity 创建一个进度对话框来接收你的进度回调。这会限制用户在您的应用程序中的输入,并允许您的服务以所需的方式继续进行。然后覆盖 Activity onResume 以检查 Service 的状态以及它是否正在运行。然后您可以立即重置对话框。

鉴于这是我的首选方法,我还要考虑到操作系统可能随时终止应用程序。因此,请确保有某种方法来检测不完整或部分同步。然后,当您的 Activity 或 Service 重新启动时,您可能会自动恢复。

于 2010-11-09T14:16:26.363 回答
5

AsyncTask如果用户去另一个活动,你不能将该对象转移到另一个活动,所以它会死掉。当说用户旋转屏幕或类似的东西时,您可以玩一些技巧,但这不会扩展到通用破坏。 AsyncTask可以随机死亡。

Google Sync 在后台作为服务运行,因为同步可能需要一段时间才能完成。您可能需要遵循他们的路径并创建自己的可以与之通信的同步服务。以下是一些如何实现的想法:

http://mylifewithandroid.blogspot.com/2008/01/about-binders.html

您绝对可以在 Service 和 Activity 之间进行通信,但要正确执行是很棘手的。

于 2010-09-28T23:01:17.240 回答
3

选择主要取决于应用程序设计。由于 AsyncTask 和 IntentService 都站稳脚跟,因此您可能希望从应用程序(用户体验)中获得什么更重要,然后选择其中一个或两者。下面提到了一些场景(主要是我在开发应用程序时遇到的)

  • 假设具有提要页面的应用程序 - 进行了多个 api 调用以使页面呈现(/getFriends、/getDates、/getPictures 等),您可以将所有此类 api 调用扭曲到具有多线程执行器的单个 AsyncTask,并且执行顺序无关紧要。与 IntentService 相比,IntentService 在单个工作线程中按顺序运行所有调用。对于具有多核的高端设备,来自 AsyncTask 的调用更有效。如果你在 UI 线程上启动 AsyncTask,那么更新 IU 就是小菜一碟(少读样板代码)。即使用户离开页面,通过智能使用不保持上下文,应用程序也不会崩溃。

  • 假设您正在尝试编写一个不需要用户查看/活动/片段的应用程序,并且显示某些内容的总执行时间不是关键任务(假设同步服务或用户通知/警报),那么 IntentService 更好选择。(在 UI 线程上启动 Asynctask 没有麻烦,这样您就不需要编写处理程序来强制更改 UI 等等等,并且减少样板代码)

根据我的经验 - 为两者编写小型应用程序并比较优缺点以获得更好的想法。(ps我建议看看谷歌的iosched应​​用程序以获得更好的想法 - 他们同时使用Asynctask和IntentService)

于 2013-02-25T23:05:52.573 回答
2

我倾向于更喜欢 IntentService + BroadcastReceiver 组合,因为它们为您提供了非常强大的控制力

如果您要更新屏幕上的内容,您必须确保 UI 正在运行。ASyncTask 崩溃立即被报告为 Android 崩溃的主要原因之一。这可以通过保留某种“activityIsAlive”变量来避免,如果活动已死,则跳过或延迟 UI 更新。

IntentService + BroadcastReceiver 组合对崩溃的抵抗力更强,因为大多数教程都告诉您在 onPause 或 onStop 时关闭 BroadcastReceiver。如果您不这样做,您将不得不再次关闭 UI 更新。有一个 runOnUiThread 命令可以帮助您进行 UI 更新。

IntentService + BroadcastReceiver 组合也更具可扩展性。您可以创建函数并扩展 BroadcastReceiver 以制作更优雅的 REST 处理解决方案。但是,与 ASyncTask 相比,它确实需要更多的管道

如果您确实延迟了 UI 更新,您可以在 OnWindowFocusChangedListener 上安装它。当该函数接收到 true 时,这意味着 UI 是活动的。

tldr; 如果您在后台运行某些东西,请在更新 UI 之前确保 Activity 和/或 Fragment 处于活动状态

2015 年编辑:也可以查看 Loaders。有点难以掌握,因为幕后发生了很多事情

于 2014-09-13T22:39:09.777 回答