在新的Android推荐架构中,BoundService + LiveData + ViewModel最佳实践

dgl*_*ano 28 android android-service android-architecture android-architecture-components android-jetpack

我一直在努力思考将Android服务放在新的Android推荐架构中的位置.我提出了许多可能的解决方案,但我无法决定哪一个是最好的方法.

我做了很多研究,我找不到任何有用的指导方针或教程.我发现关于将服务放置在我的应用程序架构中的唯一提示是@JoseAlcerreca Medium post

理想情况下,ViewModels不应该对Android有任何了解.这提高了可测试性,泄漏安全性和模块化.一般的经验法则是确保ViewModel中没有android.*导入(例如android.arch.*).这同样适用于演示者.

根据这一点,我应该将我的Android服务置于我的架构组件层次结构的顶层,与我的活动和碎片处于同一级别.这是因为Android服务是Android框架的一部分,所以ViewModels不应该知道它们.

现在,我将简要介绍一下我的场景,但只是为了让全景更清晰,而不是因为我想要这个特定场景的答案.

  • 我有一个Android应用程序,其中包含MainActivity,其中包含许多片段,所有这些片段都绑定在BottomNavBar中.
  • 我有一个绑定到myActivity的蓝牙服务及其中一个片段(因为我希望服务与Activty具有相同的生命周期,但我也希望直接从我的片段与它进行交互).
  • 该片段与BluetoothService交互以获取两种类型的信息:
    • 有关蓝牙连接状态的信息.不需要坚持.
    • 来自蓝牙设备的数据(在这种情况下,它是比例,因此重量和身体构成).需要坚持下去.

以下是我能想到的3种不同架构:

AndroidService中的LiveData Android服务范围内的LiveData

  • 具有连接状态和来自蓝牙设备的重量测量值的LiveData位于BluetoothService内.
  • Fragment可以触发BluetoothService中的操作(例如scanDevices)
  • Fragment观察LiveData有关连接的状态并相应地调整UI(例如,如果状态已连接,则启用按钮).
  • Fragment观察新重量测量的LiveData.如果新的权重测量来自BluetoothDevice,则Fragment会告诉自己的ViewModel保存新数据.它通过Repository类完成.

片段和AndroidService之间共享ViewModel 共享ViewModel arch

  • Fragment可以触发BluetoothService中的操作(例如scanDevices)
  • BluetoothService更新共享ViewModel中的蓝牙相关LiveData.
  • Fragment在自己的ViewModel中观察LiveData.

服务ViewModel 服务ViewMOdel拱门

  • Fragment可以触发BluetoothService中的操作(例如scanDevices)
  • BluetoothService在其自己的ViewModel中更新蓝牙相关的LiveData.
  • Fragment在自己的ViewModel和BluetoothService ViewModel中观察LiveData.

我很确定我应该将它们放在架构之上并将它们视为一个Activity/Fragment,因为BoundServices是Android Framework的一部分,它们由Android操作系统管理,并且它们与其他活动和片段绑定.在这种情况下,我不知道与LiveData,ViewModels和Activities/Fragments交互的最佳方式是什么.

有些人可能认为它们应该被视为一个数据源(因为在我的情况下,它使用蓝牙从一个规模获取数据),但我不认为这是一个好主意,因为我在上一段中所说的都是特别是因为它在这里所说的:

避免将应用的入口点(如活动, 服务和广播接收器)指定为数据源.相反,它们应该只与其他组件协调以检索与该入口点相关的数据子集.每个应用程序组件都是相当短暂的,具体取决于用户与其设备的交互以及系统的整体当前运行状况.

所以,最后,我的问题是:

我们应该在哪里放置我们的Android(绑定)服务以及它们与其他架构组件的关系?这些替代品中的任何一种都是好方法吗?

Jee*_*ede 9

我认为Service应该与Activity / Fragment处于同一级别,因为它是Framework组件而不是MVVM。但是由于该服务未实现LifecycleOwner及其Android框架组件,因此不应将其视为数据源,因为它可以作为应用程序的入口点。

因此,这里的难题是,有时(就您而言),Service充当数据源,该数据源将一些长时间运行的任务提供给UI。

那么,Android Architecture Component应该是什么?我认为您可以将其视为LifecycleObserver。因为,无论您在后台执行什么操作,都需要考虑LifecycleOwner的生命周期

为什么?因为,我们通常会将其绑定到LifecycleOwner (Activity / Fragments)并在UI上执行长时间运行的任务。因此,可以将其视为LifecycleObserver。通过这种方式,我们将我们的服务称为“ 生命周期感知组件 ”!


如何实施?

  1. 获取您的服务类,并为其实现LifecycleObserver接口。

  2. 将服务绑定到时Activity/Fragment,在服务类的服务连接期间,通过调用方法将服务作为LifecycleObserver添加到活动中getLifecycle().addObserver(service class obj)

  3. 现在,在服务类中获取一个接口,以提供从服务到UI的回调,并且每次数据更改时,请检查服务是否至少在Lifecycle事件上创建恢复以提供回调。

这样,我们将不需要LiveData从服务更新到更新,甚至不需要更新ViewModel (为什么要在服务中使用它?我们不需要配置更改就可以在服务生命周期中生存下来。VM的主要任务是组成数据在生命周期之间)

希望我对你说清楚!

  • 从我的角度来看,不,请勿将共享VM或LiveData用于服务。我们已经将服务lifecycleObserver设置为意味着它现在知道活动/碎片。因此,通过尊重lifecycleOwner状态使用直接回调。现在无需使用中介程序进行服务。 (2认同)
  • 服务现在正在实现 LifecycleOwner 检查 [LifecycleService](https://developer.android.com/reference/androidx/lifecycle/LifecycleService?hl=en),但现在的问题是如何在服务和另一个 Android 之间创建共享视图模型像 Activity 或 Fragment 这样的组件?@JeelVankhede (2认同)
  • @IbrahimDisouki 坦率地说,我很久以前就回答过这个问题,但现在当您提到该服务是“LifecycleOwner”时,这意味着我的答案在这种情况下没有意义,我需要再次思考并提出解决方案。我只能说,共享数据的唯一方法是遵循我们过去在任何活动和服务之间进行的传统通信。 (2认同)
  • 有人有这个答案的工作代码示例吗? (2认同)