BoundService + LiveData + ViewModel 新Android推荐架构最佳实践 [英] BoundService + LiveData + ViewModel best practice in new Android recommended architecture

本文介绍了BoundService + LiveData + ViewModel 新Android推荐架构最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在思考将 Android 服务放置在新的

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

Fragment 和 AndroidService 之间共享的 ViewModel

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

服务视图模型

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

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

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

<块引用>

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

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

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

解决方案

更新:

在得到@Ibrahim Disouki 的建议后(谢谢你) 我深入挖掘并发现了一些有趣的东西!这是背景.

O.P. 寻求解决方案Android 框架的服务组件在考虑 Android 架构组件时所处的位置".所以,这是开箱即用的 (SDK) 解决方案.

它与 Activity/Fragment 处于同一级别.如何?如果您要扩展 Service 类而不是那样,请开始扩展 生命周期服务.这背后的原因很简单,以前我们必须依赖 Activity/Fragment 生命周期才能接收更新/对 Service 执行一些上下文操作.但现在不是这样了.

LifecycleService 现在拥有自己的生命周期注册表/维护器,称为 ServiceLifecycleDispatcher,它负责服务的生命周期,这也使它成为 LifecycleOwner.

它让我们从现在开始,你可以有一个 ViewModelLifecycleService 为自己做操作&如果您遵循正确的应用程序架构并且拥有存储库模式,那么您只能获得单一的事实来源!

在 OP LifecycleService 的上下文中,现在可以维护它的 ViewModel 以执行与存储库层相关的业务逻辑,然后在另一个生命周期感知组件上,例如 Activity/Fragment 也可以使用/重用相同的ViewModel 对其进行具体操作.

请注意,这样做时,您处于拥有两个不同的 LifecycleOwners (Activity & LifecycleServie) 的状态,这意味着您无法共享视图模型LifecycleService &其他生命周期感知组件.如果你不喜欢这种方法,那么最好使用旧的回调方法,当数据准备好提供服务时回调到 Activity/Fragment 等.


已过时:

(建议不要通读)

在我看来,Service 应该与 Activity/Fragment 处于同一级别,因为它是框架组件&不是MVVM.但由于该服务没有实现 LifecycleOwner 并且它是 Android 框架组件,不应将其视为数据源,因为它可以作为应用程序的入口点.

因此,这里的困境是有时(在您的情况下),Service 充当数据源,将一些长时间运行的任务的数据提供给 UI.

那么Android 架构组件应该是什么?我认为您可以将其视为 LifecycleObserver.因为,无论您在后台做什么,您都需要考虑 LifecycleOwner 的生命周期.

为什么?因为,我们通常会将它绑定到 LifecycleOwner (Activity/Fragments) &在 UI 之外执行长时间运行的任务.因此,它可以被视为LifecycleObserver.通过这种方式,我们将我们的服务作为生命周期感知组件"!


<块引用>

如何实施?

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

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

  3. 现在,在服务类中使用一个接口来提供从服务到 UI 的回调,每次数据更改时,请检查您的服务是否至少有生命周期事件 createresume 提供回调.

这样,我们就不需要 LiveData 更新到服务,甚至不需要 ViewModel (为什么我们需要它来服务?我们无需更改配置即可在服务生命周期中生存.VM 的主要任务是在生命周期之间整合数据).


旁注:如果你认为你有长时间运行的后台操作,那么考虑使用 WorkManager. 使用这个库后,你会觉得服务应该是现在标记为已弃用!(只是一个随意的想法)

I been struggling a lot thinking about where to place Android Services in the new Android recommended Architecture. I came up with many possible solutions, but I cannot make up my mind about which one is the best approach.

I did a lot of research, and I couldn't find any useful guideline nor tutorial. The only hint I found about where to place the Service in my app architecture is this one, from @JoseAlcerreca Medium post

Ideally, ViewModels shouldn’t know anything about Android. This improves testability, leak safety and modularity. A general rule of thumb is to make sure there are no android.* imports in your ViewModels (with exceptions like android.arch.*). The same applies to presenters.

According to that, I should place my Android Services on the top of my Architecture Components hierarchy, at the same level as my Activities and Fragments. That's because Android Services are part of the Android framework, so ViewModels shouldn't know about them.

Now, I will explain briefly my scenario, but only to make the panorama clearer, not because I want an answer for this specific scenario.

  • I have an Android Application that has a MainActivity with many fragments in it, all of them tied together in a BottomNavBar.
  • I have a BluetoothService bound to myActivity and one of its fragments (because I want the Service to have the same lifecycle as the Activty but I also want to interact with it directly from my fragment).
  • The fragment interacts with the BluetoothService to get two types of information:
    • Information about the state of the Bluetooth connection. Doesn't need to be persisted.
    • Data that comes from the Bluetooth Device (it is a Scale, so weight and body composition in this case). Needs to be persisted.

Here are the 3 different architectures I can think of:

LiveData inside AndroidService

  • The LiveData with the state of the connection and with the weight measurements coming from the Bluetooth Device are inside the BluetoothService.
  • The Fragment can trigger operations in the BluetoothService (scanDevices for example)
  • The Fragment observes the LiveData about the state of the connection and adapts the UI accordingly (for example, enable a button if the state is connected).
  • The Fragment observes the LiveData of the new weight measurements. If a new weight measurement comes from the BluetoothDevice, the Fragment then tells its own ViewModel to save the new data. It is done via a Repository class.

Shared ViewModel between fragment and AndroidService

  • The Fragment can trigger operations in the BluetoothService (scanDevices for example)
  • The BluetoothService updates the Bluetooth related LiveData in the shared ViewModel.
  • The Fragment observes the LiveData in its own ViewModel.

Service ViewModel

  • The Fragment can trigger operations in the BluetoothService (scanDevices for example)
  • The BluetoothService updates the Bluetooth related LiveData in its own ViewModel.
  • The Fragment observes the LiveData in its own ViewModel and the BluetoothService ViewModel.

I am pretty sure I should place them on top of the architecture and treat them just like an Activity/Fragment, because BoundServices are part of the Android Framework, they are managed by the Android OS and they are bound to other Activities and Fragments. In that case, I don't know what's the best way to interact with LiveData, ViewModels and Activities/Fragments.

Some might think that they should be considered as a DataSource (since in my case it's getting data from a scale using Bluetooth), but I don't think this is a good idea, because of all what I've said in the previous paragraph and specially because of what it says here:

Avoid designating your app's entry points—such as activities, services, and broadcast receivers—as sources of data. Instead, they should only coordinate with other components to retrieve the subset of data that is relevant to that entry point. Each app component is rather short-lived, depending on the user's interaction with their device and the overall current health of the system.

So, finally, my question is:

Where should we place our Android (Bound) Services and what is their relation with the other architectural components? Is any of these alternatives a good approach?

解决方案

Updated:

After getting suggestion from @Ibrahim Disouki (Thank you for that) I dig deeper and found out something interesting! Here's background.

O.P. seeks for solution "Where Service component of Android Framework stands considering Android Architecture Components". So, here's out the box(SDK) solution.

It stands at the same level as Activity/Fragment. How? If you're extending Service class though rather than that, start extending LifecycleService. Reason behind that is simple that previously we had to rely on Activity/Fragment lifecycle in order to receive updates/do some contextual operations on Service. But now it's not the case.

LifecycleService now has it's own lifecycle registry/maintainer called ServiceLifecycleDispatcher which takes care of lifecycle of service which also makes it LifecycleOwner.

It leaves us in condition that from now on, You can have a ViewModel to LifecycleService doing operations for itself & if you're following proper app architecture and having repository pattern leaves you to single source of truth!

In context of O.P. LifecycleService now can have ability to maintain it's ViewModel to do business logic related to repository layer, and later on another lifecycle aware component like, Activity/Fragment can also consume/reuse same ViewModel to have their specific operations to it.

Please note that by doing so, you're in state of having two different LifecycleOwners (Activity & LifecycleServie) which means you can't share view models between LifecycleService & other lifecycle aware components. If you don't like approach then be good with old callback kind of approach having callbacks back to Activity/Fragment from service when data is ready to serve etc.


Obselete:

(I suggest not to read through)

In my opinion, Service should be on same level as Activity/Fragment, because it's Framework component & not MVVM. but because of that Service doesn't implements LifecycleOwner and it's Android Framework Component, it shouldn't be treated as data source because it can be entry point to application.

So, dilemma here is that sometimes (In your case), Service acts as data source which provides data from some long running task to UI.

So what it should be in Android Architecture Component? I think you can treat it as LifecycleObserver. because, no matter what you do in background, you'll need to consider about lifecycle of the LifecycleOwner.

Why? because, we usually do bind it to LifecycleOwner (Activity/Fragments) & to do long running tasks off the UI. So, it can be treated like LifecycleObserver. In such a way we made our Service as "Lifecycle aware component" !


How you can implement it?

  1. Take your service class and implement LifecycleObserver interface to it.

  2. When you bind your service to Activity/Fragment, during your service connection of your service class, add your service to your activity as LifecycleObserver by calling method getLifecycle().addObserver(service class obj)

  3. Now, Take an interface in service class to provide callback from service to your UI and every time your data changes, check that if your service has at least on Lifecycle event create or resume to provide callback with.

In such a way, we won't require LiveData to update to from service and even no ViewModel (Why do we need it for service? We don't need configuration changes to survive on service lifecycle. And main task to VM is that to consist data between lifecycles).


Side Note: If you think you're having long running background operations, then consider using WorkManager. After using this library, you'll feel like Services should be marked as deprecated by now! (Just a random thought)

这篇关于BoundService + LiveData + ViewModel 新Android推荐架构最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆