2

好的,一段时间以来,我一直在研究解决此问题的最佳方法,所以让我为您分解一下我的需求和发现。

需求:

  • 一个活动 [SendMsg] 组成一个消息正文,其中可能包括最多 5MB 的图像附件。
  • 当用户发送此消息时,消息必须上传到我的服务器
  • 此上传必须同步发生,因为我阻止用户使用该应用程序,直到它完成或失败
  • 完成后,如果发送成功,则 SendMsg Activity 将被销毁 - 否则会显示错误对话框
  • 考虑到任何手机旋转或主页按钮按下/电话等,上传和用户体验必须保持不变

这里的最后一个子弹原来是最难的。

发现:

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

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

很明显,我想要的是某种共享内存存储,我可以在其中保存来自 Activity 的数据。然后 Activity 可以向 Service 发出信号,表明它可以继续并上传该数据。

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

另一个问题出现在上传完成但没有活动绑定到服务时,但我想我可能已经解决了这个问题。请让我知道以下是否有意义:

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

3 回答 3

4

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

然后,您可以在 WakeLock 的帮助下使用 IntentService 完成要求。我倾向于避免在 Android 中绑定服务,因为它们由于屏幕旋转而难以使用。只需在启动.IntentService

在我看来,从您的 Service 与您的 Activity 进行通信的最佳方式是使用PendingIntent. 基本上,您从 Activity 启动服务,并传入PendingIntent启动服务的 Intent。当您的服务完成其工作或失败时,您将调用send()PendingIntent。onActivityResult()然后,您的 Activity 将在其方法中获得回调。

这样做有几个好处:

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

我有一个演示应用程序来展示这种方法。基本上,您有一个Activity为一些工作加注星标,并使用进度对话框阻止 UI。如果屏幕旋转,此对话框将再次显示。工作在Service中完成,Service将PendingIntent返回给 Activity。

您工作的最后一部分是确保在上传运行时设备不会进入睡眠状态。Mark Murphy 编写了一个很好的示例服务实现,它使用 aWakeLock来确保不间断地完成工作。

于 2012-12-05T18:15:22.943 回答
1

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

我还将利用与前台服务一起使用的通知来让用户知道他们上传的状态。

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

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

于 2012-12-05T18:01:43.987 回答
0

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

于 2012-12-05T18:01:14.610 回答