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
UPDATE: This is the approach I personally went with at the time because it worked well and allowed me to get it done relatively fast. However, I suggest following the updated answer by Jeel Vankhede for what seems to be a more "idiomatic" implementation.
- 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.
- 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?
LifecycleObserver
interface. – Thumbscrew