Androiddevise注意事项:AsyncTask vs Service(IntentService?)

我正在devise一个Android应用程序,将需要执行以下步骤:

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

同步过程第一次运行,可能需要10-20分钟。 初始同步后,更less的数据将被传输和存储,我期望过程需要1-2分钟或更less。

我一直在做很多关于android的AsyncTask和使用服务的各种示例的阅读…但是我不完全理解select一个devise的devise考虑和折衷。 我目前有我的演示项目使用AsyncTask存根。 在观看(大部分)开发Android REST客户端应用程序之后: http : //code.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html#我对这里描述的devise模式感到困惑感觉过于复杂,也许是因为我只是“不明白”而已。

我来自java,spring,web和桌面应用程序背景。 对于手持设备的思考和devise对我来说是相当新的。 (当屏幕布局被改变时会发生什么?当我正在运行同步时,电话铃响时会发生什么?)如果初始同步是一个长时间运行的过程,那么有两个步骤,是否有更好的方法我想想问题 – >解决scheme,用户体验,用户对电话上运行的应用程序的期望?

很想听到一些更有经验的Android开发人员谁已经在这些问题上摔angular。

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

当然你需要使用一个Service

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

一些开发人员通过安排一个静态的东西来进行长时间的动作。 有些人推荐使用Application实例。 这是因为静态的东西和Application存在,而整个应用程序进程存在。 但是这些是不正确的解决方法。 Android的进程也可能在操作系统决定是时候终止。 Android操作系统有自己的想法,它可以杀死什么,以什么顺序。 所有的过程分为5个级别的“killability”。 这里是指定这些级别的文档 。 阅读这里很有趣:

因为运行一个服务的进程比具有后台活动的进程要高,所以启动一个长时间运行的活动可能会很好地启动该操作的服务,而不是简单地产生一个线程 – 特别是如果该操作可能会比活动。 这样的例子是在后台播放音乐并将相机拍摄的图片上传到网站。 使用服务保证操作至less具有“服务过程”优先级,而不pipe活动发生了什么。

用户启动长时间运行的活动应显示一个ProgressDialog ,以确保用户在运行时不会执行任何其他操作。 指南在这里 。

另外,如果你的Activity目前是不可见的,你很可能要使用NotificationManager来通知用户你长时间的动作完成(或失败)。 这是NotificationManager信息的开始。

为了最好地决定如何处理您的情况,您必须考虑多种因素。 这听起来像是你需要对这两种方法进行很好的比较……所以这里列出了一些相似之处,以及在手持设备上工作时必须考虑的差异和其他因素。

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

一个AsyncTask总是从UI线程实例化。 它只允许特定的callback,但是为了相对较短的事务(与专用的单独的线程服务相比)简化了multithreading的过程,这些事务与活动所执行的动作有内在的联系。 无论用户何时更改活动,AsyncTask都会处于“暂停”状态,甚至可能会因为您的Activity没有任何UI线程而死亡。

我最关心的是,如果应用程序第一次需要10-20分钟,我会假定用户将暂时更改任务或者设置电话直到完成(可能会导致所有的如果电话睡觉,同样的复杂情况)。 考虑到这个考虑,绑定到您的活动的线程服务可能是您的最佳select。 为了保护您的用户界面,我会为您的活动创build一个进度对话框,以接收您的进度callback。 这限制了您的应用程序中的用户input,并允许您的服务以需要的方式继续。 然后覆盖活动onResume来检查您的服务的状态,如果它正在运行。 然后你可以立即重置对话框。

鉴于这是我首选的方法,我也会考虑到操作系统可能会随时杀死应用程序。 所以请确保有一些方法来检测不完整或部分同步。 然后,当您的活动或服务重新启动时,您可以自动恢复。

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

Google Sync在后台作为服务运行,因为同步可能需要一段时间才能完成。 您可能需要遵循其path并创build可与之通信的自己的同步服务。 这里有一些想法如何做到这一点:

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

您肯定可以在服务和活动之间进行沟通,但要做到这一点很困难。

select主要取决于应用程序devise。 由于AsyncTask和IntentService都是站稳脚跟的,所以您可能需要从应用程序(用户体验)中获得更多的重要信息,然后select其中之一或两者。 下面提到了一些场景(主要是我在开发应用时经历的)

  • 假设具有提要页面的应用程序 – 使用多个api调用来使页面呈现(/ getFriends,/ getDates,/ getPictures等),您可以使用multithreading执行程序将所有此类api调用转换为单个AsyncTask,执行顺序无关紧要。 与在单个工作线程中依次运行所有调用的IntentService相反。 对于具有多核的高端设备,AsyncTask的调用更有效。 如果你在UI线程上启动AsyncTask,那么更新IU是一块蛋糕(读取较less的锅炉板代码)。 即使用户离开页面,智能使用不保持上下文,应用程序也不会崩溃。

  • 假设您正在尝试编写一个不需要用户在view / activity / fragment中的应用程序,并且显示某个内容的总执行时间不是关键任务(假设同步服务或用户通知/警报),那么IntentService是更好的select。 (没有麻烦在UI线程上启动Asynctask,以便您不需要编写处理程序来强制更改UI等等,而不是锅炉板代码)

根据我的经验 – 为两者编写小应用程序,并比较优点和缺点,以获得更好的想法。 (ps我build议看看从谷歌iosched应​​用程序得到一个更好的主意 – 他们同时使用Asynctask和IntentService)

我倾向于selectIntentService + BroadcastReceiver组合,因为它们给你一个非常强的控制度

如果你正在更新屏幕上的内容,你一定要确保UI正在运行。 据报道,ASyncTask崩溃是Android崩溃的主要原因之一。 这可以通过保持某种“activityIsAlive”variables来避免,如果活动已经停止,则跳过或延迟UI更新。

IntentService + BroadcastReceiver组合对崩溃更有抵抗力,因为大多数教程都告诉你closuresBroadcastReceiver onPause或onStop。 如果你不这样做,你将不得不closuresUI更新。 有一个runOnUiThread命令可以帮助你做UI更新。

IntentService + BroadcastReceiver组合也更具可扩展性。 您可以创build函数并扩展BroadcastReceiver以创build更加优雅的REST处理解决scheme。 但是,它确实需要更多pipe道与ASyncTask

如果你确实延迟了UI更新,你可以在OnWindowFocusChangedListener上使用它。 当这个函数接收到的时候,这意味着UI是活着的。

tldr; 如果您在后台运行某些内容,请确保“活动”和/或“片段”在更新UI之前保持活动状态

2015编辑:检查装载机以及。 有点难以掌握,因为幕后有很多事情要做