众所周知,Android 将我们的应用程序组件(活动、服务)置于随时被杀死的威胁之下。如果您想提供一个健壮、无泄漏的解决方案,同时保持代码干净并解决关注点分离,这会使事情变得非常复杂。
问题:
一个活动启动一个耗时的任务(以 aRunnable
或AsyncTask
任何其他机制的形式)。应显示一个进度对话框。该任务将打开几个连接,但它应该具有更新进度条的方法,并且它可能需要在完成的中途显示一个选择对话框。它还应该能够在发生错误或完成时关闭对话框并显示 Toast。
当一个 Activity 被杀死并稍后重新创建一个新实例时,我可以想到两个选项:
尝试终止正在运行的任务,并在创建新的替代活动实例时生成另一个任务实例。对于长时间运行的任务,这不是一个选项,因为从用户的角度来看,启动任务并看到进度条指示器在没有明显原因的情况下从 80% 回到 0% 是不可接受的。然而,这是Romain Guy 在 Shelves 示例中采用的方法。显然,这是官方开发人员指南中推荐的方法。
保持任务运行:所以我们可以有一个活动订阅(并可能开始)任务以进行更新
onResume
,并在 取消订阅(并可能暂停)它onPause
。
遵循第二个选项意味着我们应该防止任务被收集,以防活动被暂时破坏。例如,我们可以在自定义 Application 类中声明它,或者甚至将它作为服务提供给应用程序的其余部分(使用 Singleton?Android 服务?)不过,我不喜欢这个,因为任务是仅由活动使用,因此使其对其他类可用是没有意义的。另一方面,Android 服务也必须处理生命周期。
选项 #2 还涉及确保不泄露旧活动。如果没有活动,我们不应该尝试更新 GUI。整个想法应该是线程安全的。最后,在我们确定不再需要该任务后,该任务不应保留在内存中。但同时,如果初始活动被破坏,任务继续运行,并且新的替代活动启动,任务必须立即更新GUI并显示任务当前状态(或结果以防它完成)。
在没有显示活动时任务可能正在运行的事实是另一个需要处理的问题,因为我们可能需要在某些时候同步用户交互(选择对话框)。如果 Activity 能够在到达 时立即暂停任务,则可以解决此问题onPause
,但任务可能需要一些时间自行暂停,甚至无法暂停。
我知道以前也有人问过类似的问题,但我并不是专门询问如何解决问题,而是建议推荐什么样的设计以实现松散耦合并尽可能地将活动与任务隔离开来。
简而言之:
- 这是 Android 开发中反复出现的问题,之前可能有人提出了一个聪明的设计。是否有设计模式或经过良好测试的库来简化这一点?
- 如果您要实现#2,您会为任务选择哪个类(Runnable、Service 等)以及它将如何与活动通信?
PS 请不要发布基于“orientation | keyboardHidden” hack XD 的解决方案。除此之外,任何帮助将不胜感激。
更新:
我的第一次尝试有点混乱。该应用程序是一个蓝牙打印实用程序,它涉及检测 BT 状态(如果禁用,则要求用户启用它),检索配对设备(如果有多个设备,则要求用户选择一个),然后发送数据最后通知用户结果。由于这个任务是 80% 的 IO 代码,20% 与 GUI 相关的操作,我不得不在任务的开始和结束时对 GUI 代码进行分组,然后将其从任务中移回活动中。我有一个IntentService
可以完成繁重工作,然后通过以下方式向活动报告BroadcastReceiver
. 这解决了大部分问题,但这样的设计存在一些问题。首先,所有这些常量字符串都用作键来从输入和输出 Intent 中放置和检索字段,这引入了语义耦合。我会在活动<->服务通信中首选类型安全。而且我还必须解决如何将复杂的自定义对象传递给 Intent 中的服务,现在我被 Parcelables 和原始参数困住了。最后,活动和服务都使用相同的 API(蓝牙),我宁愿将所有与 BT 相关的代码放在一个类中。我想我会放弃这种设计,并使用基于线程的自定义打印队列再试一次,尽管它会更难处理被杀死的活动。