在活动和服务之间共享大量数据

时间:2012-12-05 17:51:06

标签: android multithreading service

好的,我一直在研究解决这个问题的最佳方法,所以让我为你分解我的需求和发现。

需要:

  • 活动[SendMsg]组成一个邮件正文,其中可能包含最多5MB的图片附件。
  • 当用户发送此消息时,必须将消息上传到我的服务器
  • 此上传必须同步发生,因为我阻止用户使用应用程序直到完成或失败
  • 完成后,如果发送成功,将销毁SendMsg活动 - 否则会显示错误对话框
  • 在任何电话轮换或主页按键按下/拨打电话等情况下,上传和用户体验必须保持不变

这里的最后一颗子弹是最难的。

结果:

我想过只是在静态AsyncTask中完成这项工作,但我认为这对我不起作用 - 状态变得非常混乱,似乎我无法保证操作系统在应用程序出现时不会杀死线程在后台。

我决定使用一个服务,在服务中创建它并绑定/解除绑定。该服务生成AsyncTask,完成工作,然后根据其结果(SUCCEED / FAIL)发出活动信号。除了我的大消息之外,这种范例似乎工作正常。服务/活动通信消息通信不是用于编组这样大的有效载荷。 *注意:如果不清楚,当用户点击发送时,该表格数据和文件必须提供给服务。在某些情况下,这是从相机拍摄的图像,该图像不能并且不能存在于磁盘上以用于应用程序。

显然我想要的是某种共享内存存储,我可以从Activity中保存数据。然后,活动可以通知服务它可以继续并上传该数据。

内存中是否存在这样的共享区域?我可以从服务获取Application对象并将数据存储在那里吗?

另一个问题出现在上传完成但没有活动绑定到服务但是我想我可能已经想出了这个。如果以下内容有意义,请告诉我:

  1. 服务完成上传
  2. 服务检查以确定当前是否绑定了一个活动
  3. 如果是,则返回错误消息,其中Activity通过其消息队列处理
  4. 如果不是,则将返回码存储在该共享内存区域中,并在其中标记一个布尔值
  5. 创建/恢复客户端Activity时,应首先检查此布尔值以查看该进程是否已完成。如果是这样,将一个Message分配给它自己的处理程序并像以前一样处理代码

3 个答案:

答案 0 :(得分:4)

为了处理你的内存需求,我可能会将Map UUID用于包含所有消息详细信息的持有者类。将此Map存储为Application子类中的成员变量,或者作为静态变量。当您的任务完成或失败时,确保将其清除。如果您确定不会同时有多个此类请求,也许您可​​以使用单个类而不是Map或列表。

然后,您可以在IntentService的帮助下使用WakeLock来完成您的要求。我倾向于避免在Android中绑定服务,因为它们很难用于屏幕旋转。只需从启动IntentService的Intent中的Map传递标识符。

在我看来,从服务回复到您的活动的最佳方式是使用PendingIntent。基本上,您从Activity启动服务,并在启动服务的Intent中传入PendingIntent。当您的服务完成其工作或失败后,您可以在PendingIntent上调用send()。然后,您的Activity将在其onActivityResult()方法中获得回调。

这样做有几个好处:

  • 这很简单。您可以在IntentService中的单独线程中完成一个长时间运行的任务,并在UI线程完成时收到通知。
  • 这支持屏幕旋转!你可以随心所欲地旋转你的活动,你仍然可以在onActivityResult()中获得回调。相反,即使你finish()你的活动并在发送PendingIntent之前开始一个新活动,它也不会被传递,这几乎总是你想要的。

我有一个显示此方法的demo application。基本上,你有一个Activity明星有些工作,并通过进度对话框阻止UI。如果屏幕旋转,将再次显示此对话框。该工作在Service完成,该nice examplePendingIntent发送回活动。

您的工作的最后一部分是确保设备在上传运行时不会进入休眠状态。 Mark Murphy编写了Service implementation和{{3}},使用WakeLock来确保工作不间断地完成。

答案 1 :(得分:1)

首先,您还应该将服务切换到通过startService()调用触发的前台服务(而不是绑定到服务)。这将确保服务尽可能长时间保持活力。绑定到服务将在您的活动完成后停止服务(这可能在用户离开您的应用时发生)。

我还会利用前台服务使用的通知让用户知道他们上传的状态。

要将信息从服务传递回Activity,您可以查看ResultReceiver类。具体来说,研究一下Google在其IO应用程序中实现的DetachableResultReceiver范例。

由于除了通信要求之外还有大量内存要求,您可能只想创建一个单例对象来共享活动和服务之间的数据和状态。

答案 2 :(得分:0)

使用静态变量创建一个类,并让您的活动将所有值设置为该类。然后启动一个IntentService并让该服务查看上面的类。一旦IntentService处理完该消息,它就会广播该消息,如果有任何活动在等待广播,他们将收到该消息。