android - IntentService android下载并返回文件到Activity

标签 android service download

我遇到了一个相当棘手的情况,我正在尝试确定最佳设计。基础知识是这样的:

  • 我正在设计一个消息传递系统,其界面与电子邮件类似。
  • 当用户点击带有附件的消息时,会生成一个 Activity ,显示该消息的文本以及表示还有附加附件的回形针。
  • 此时,我开始预加载附件,以便当用户单击它时,加载速度会更快。
  • 目前,当用户单击附件时,它会提示加载对话框,直到下载完成,此时它会加载一个单独的附件查看器 Activity ,并传入 bmp 字节数组。
  • 我不想将附件保存到持久存储中。

我遇到的困难是支持旋转以及主页按钮按下等。下载当前是通过线程和处理程序设置完成的。

我希望流程如下:

  • 用户像以前一样加载消息,像以前一样预加载附件开始(用户不可见)。
  • 当用户点击附件链接时,会立即生成附件查看器 Activity 。
  • 如果下载完成,则会显示图像。如果没有,则此 Activity 中会显示一个对话框,直到完成并可以显示为止。请注意,理想情况下下载永远不会重新启动,否则我会在预加载上浪费周期。

显然,我需要一些持久的后台进程,能够继续下载并能够回调任意绑定(bind)的 Activity 。看起来 IntentService 几乎满足我的需求,因为它在后台线程中工作并且具有服务(非 UI)生命周期。但是,它能满足我的其他需求吗?

我注意到我想要做的事情的常见实现是从调用者 Activity 获取 Messenger,以便可以将 Message 对象发送回调用者线程中的 Handler。这一切都很好,但是在我的情况下,当调用者 Activity 被停止或销毁并且当前 Activity 的 Activity (附件查看器)正在显示时会发生什么? 是否有某种方法可以将新的 Activity 动态绑定(bind)到正在运行的 IntentService,以便我可以将消息发送回新的 Activity?

另一个问题是关于 Message 对象的。我可以用这个包发回任意大的数据吗?例如,我不需要发回“文件已下载”,而是需要发回下载文件本身的字节数组,因为我不想将其写入磁盘(是的,情况必须如此)。

非常感谢任何有关实现我想要的行为的建议。我使用 Android 的时间并不长,而且我经常对如何在 Activity 生命周期中最好地处理异步进程感到困惑,尤其是在方向更改和按下主页按钮时......

最佳答案

有多种方法可以解决这个问题。你是对的,我认为你显然需要一个针对这种情况的服务来将下载过程与可能来来往往的 Activity 分离。为此,您需要在此服务中实现一些下载队列,并且 IntentService 提供了开箱即用的此行为,因此您可以使用它。 IntentService 的唯一缺点是取消您之前为其发布的作业并不那么容易。

我不会序列化下载的数据,但是,这听起来不太有效,尤其是在处理大量二进制数据时。您可以将下载的数据写入内存中的 LRU 缓存,并为其分配一个 ID,Viewer Activity 可以通过该 ID 来获取此下载的数据。

您还可以使用广播 Intents 向服务中的查看器 Activity 发出信号,表明具有特定 ID 的下载已完成。这将确保查看 Activity 和下载 Service 之间的松散耦合。

所以事情会是这样的:

  1. 用户打开带有附件的消息。
  2. 您将此附件的下载作业发布到下载器 IntentService,并为此附件分配唯一的 ID。
  3. 当用户点击附件时,您将启动查看器 Activity ,并将附件的唯一 ID 作为此 Activity 的参数传递。
  4. 查看器 Activity 打开,它立即检查缓存以查找要显示的内容。如果尚未完成,它会显示一些加载图形,并等待下载器 IntentService 通过广播 Intent 喊出“xy ID 已完成”。如果 xy ID == 传递到此查看器 Activity 中的 ID,您将从缓存中获取现在完全下载的内容并将其呈现给用户。

编辑:

至于缓存,你必须做出一些选择。我认为这本身就是一个相当广泛的主题,所以我将根据我之前的项目在这里写一些想法。

上面,我只提到了内存中 LRU 缓存。这将存在于自定义应用程序对象中,或者作为单例。这是使用邪恶的全局状态,但我认为在这种情况下这是合理的。优点是您不需要在任何地方序列化下载的数据:下载完成后,内存中就有内容,您可以立即从查看器 Activity 中访问它。缺点是,这些数据只有在未从缓存中删除或系统不会因内存不足而终止应用程序进程时才可用。

为了避免在丢失此 volatile 内存缓存的内容时重新下载数据,您需要为其添加一个持久层。例如。将下载的数据写入application's cache directory 。这带来了将下载的数据写入磁盘的开销,但至少您以后可以访问它,即使系统杀死了您的进程。您可以使用 2 级缓存方法将此持久缓存与内存中缓存结合起来,也可以选择其中之一。我建议查看一些广泛使用的图像下载器库,它们实现了这种行为以获取灵感,例如Universal Image Loader .

关于android - IntentService android下载并返回文件到Activity,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13463463/

相关文章:

javascript - location = "file.exe",下载时显示下载大小?

java - 如何在 OpenNLP 中初始化 token 模型?

ubuntu - 使用 wget 命令将文件下载到 PC

android - 带 IP 地址的 TCP 服务器

android - 如何提取一些单元测试来分离 gradle 测试任务?

android - 如何在 android 中使用 JUnit 测试 webService 调用代码?

android - 管理 Android 应用程序的生命周期

android - 与安卓服务通信

android - 防止用户返回到上一屏幕 StackNavigator

java - 如何将大型 Java 应用程序分解为组件?