Android Ble client app architecture - android

it's more a general question rather than a specific one.
Basically I'm developing an Android app which communicates with Ble Peripheral Device.
I handle Ble communication using RxAndroidBle library. As for the general pattern, I decided to try Mosby MVI, however
that's not that important.
What I did so far is I created BluetoothManager class which is responsible for performing all the operations
on the Ble Device. This class is a Singleton (I know it's not recommended on Android) and I scoped it using Dagger,
that this is injected only to those interactors that should perform some Ble communication.
This class returns Observables with some POJOs, which are transformed to ViewStates in interactor and than moved higher to the UI.
Subscriptions are in the presenters following Mosby MVI pattern.
Basically thanks to that I treat this Ble Device as a regular data source, same as some retrofit service or any db.
And that was totally fine as long as I was performing atomic operations like writing and reading some single characteristics.
The problem is when I need to fire up some kind of a synchronization that may take quite a lot of time, should be done on background,
should NOT be bound to UI, however on some screens user should be able to see the progress.
Here I started to think about using Android Service and putting all the Ble Communication logic there,
however in my opinion using Android service breaks any attempts of logic separation and I couldn't find a good way to fit it there.
Third option was having a service for synchronization and preserving BluetoothManager for atomic operations bounded to UI, however
I think it's messy and I would be nice to have all the Ble stuff in one place.
I know it's long but it all goes to one question -> what would be the best pattern to follow when communicating with Ble device on Android
to preserve layers separation and keeping it as independent as possible.
I could not find any good articles about handling that, if there are any they are quite out dated, not using Rx approach.
If it's too generic, I can specify some more details, but I'm looking more for an architectural advice rather than code snippets.

What about something like this:
instead of subscribing in presenter to bluetooth directly, introduce a class BleRepository
Then BleRepository provides a metod Observable<Foo> (Foo is whatever data your Presenter / UI should see) and operations to execute stuff like doA(). Something like this:
interface BleRepository {
// Read Data
Observable<Foo> getDataObservable();
// Write Data operations
Completable doA();
Completable doB();
}
So the Presenter subscribes to BleRepository instead to bluetooth connection directly.
So now whenever you do a "write operation" you just execute it but you always read new data from getDataObservable() even if the write operation itself returns new data, reading data always goes through getDataObservable().
So BleRepository is basically just a public API your presenter uses. The Presenter doesn't know about the actual Bluetooth connection. So what you can do next is moving the actual bluetooth connection into an android service, lets call it BluetoothService. Then BluetoothService get's connected and whenever the sync runs or whatever else your connection receives / sends, it emits that data back to BleRepository.getDataObservable() which is subscribed by the service. You just have to ensure that both Service and Presenter "share" the same BleRepository instance. i.e. use dagger to inject the same instance or make it a singleton ... whatever works best for you.
Depending on your usecase you can also make the BluetoothService subscription aware like start the android service in RxJavas onSubscribe and stop the service in on unsubscribe / onTerminal. But it sounds like your usecase is slightly different so that Bluetooth is still connected even if Presenter / view has been destoryed, right? Whatever, the idea is use Service (Services if it makes sense for your proble) but they all somehow push the data into BleRepository that then delivers the data to the Presenter.

Related

Bound Services in MVVM pattern

I'm working on an Android app (in Java) and trying to use Google's recommended application architecture, but I can't seem to figure out where services fit in to this architecture. I've done a lot of looking online and there is no clear consensus on how this should be done.
For context, my application communicates with a BLE device. I've created BLEService which extends Service that establishes the connection with the device, and provides methods send data to the device. The device can also send data back (and thus needs to notify the app when data is received).
My question is, where should the ServiceConnection reside, and how should it be stopped/started? From my research, there are a couple options that each have their pros and cons.
The Service is started/stopped in the Activity, the Activity observes events from Service. The Activity forwards the events to the ViewModel for processing. This pattern keeps all of the Android components together, but gives more responsibility to the View than I believe it should. The View should only be responsible for handling the UI.
The Service is stopped/started in the ViewModel (perhaps by extending AndroidViewModel). The ViewModel observes events from the Service and processes the events. This pattern is nice because the ViewModel is handling the business logic, however if Service implements its events via LiveData, Google states that the ViewModel must not observe LiveData. Another option is for the Service to implement events via something like EventBus, but there are a lot of people against using EventBus because it is easy to abuse. I have also heard that ViewModel should not have any Android-specific code in it for testing purposes.
The Service exists in some sort of Repository/Model. The ViewModel forwards its sends and observes events from the Repository/Model. This solution is nice because interfacing with a Bluetooth device does seem like it fits the intended purpose of what a Model is. However, it suffers the same issue that the ViewModel must not observe LiveData. I have seen Transformations.switchMap suggested in this case, which causes a LiveData in the ViewModel to be updated in response to a change in a LiveData from the repository. I'm not totally clear on using this strategy, or how it would function in my specific use-case. There's also the issue that the repository needs access to Context, and I have heard it's bad practice to hold on to an instance of Context. Furthermore, I have also read that a Repository should not hold on to callbacks from the ViewModel.
I'm sure there's no perfect solution, but if someone could point me in a direction of best practices, particuarly in my use-case, that would be immensely helpful.

Using Kotlin Coroutines to replace LocalBroadcastManager for Firebase messaging

When using Firebase Cloud Messaging on Android, it is often desirable to notify the current Activity of an incoming push notification. One of the recommended ways to do this has been to use LocalBroadcastManager to send an Intent from the FirebaseMessagingService implementation to the Activity (StackOverflow example answer).
However, as of version 1.1.0-alpha01 (2018-12-17), LocalBroadcastManager is deprecated:
LocalBroadcastManager is an application-wide event bus and embraces layer violations in your app: any component may listen events from any other. You can replace usage of LocalBroadcastManager with other implementation of observable pattern, depending on your usecase suitable options may be LiveData or reactive streams.
While it is highly likely that this class will remain available for a while longer, I would like to start cleaning up our applications anyway, so I want to migrate to something better before Google actually removes the old way.
Right now, there are two main roles that these local broadcasts have in our apps:
Update the UI with the new data from the push notification. The way this worked was that each Activity that cares about the incoming push data has a broadcast receiver that listens for the appropriate message and updates its own view data.
Force the user to log out if the server sends a notification to end the session. This works with each activity having an instance of a broadcast receiver that listens for a logout event, ends the Activity, and starts the Login Activity.
As I see it, these use-cases have issues with both of their suggested alternatives:
LiveData is easiest to use in an Activity or Fragment as part of a ViewModel. However, ViewModel is only meant to be used from those classes that directly deal with the UI. Accessing the ViewModel from within the FirebaseMessagingService takes an ugly hack and is a really bad idea from an architectural perspective. Also, different activities and fragments have different ViewModel objects, and I don't want the service to need to access them all.
I can create a Kotlin object (a.k.a. Singleton) with a bunch of LiveData properties, have the FirebaseMessagingService update those LiveData objects from the incoming messages, and have the Activity observe those changes and copy them into its own ViewModel's LiveData properties. The problem with that is twofold: first, it requires me to have two identical LiveData objects for each piece of data, one in the ViewModel and one in the object; and second, it doesn't help me with handling the "log out event", because LiveData is meant to handle changing data, not listening to a stream of events. (I may be able to handle the second issue using this LiveData Event Wrapper, but that still feels like a bad hack over something that isn't meant to work this way.)
While reactive streams, such as RxJava, will probably do what I need, I already forced my team to learn Kotlin, Android Databinding, Android ViewModel, and a bunch of other new stuff in the last few months, and I don't think they can take much more. RxJava is also a large thing to add for just this one use, and we have no plans to rewrite the entire application to take advantage of it in order to justify its addition.
One suggestion I found was to use Kotlin Coroutines with Channels or Flows. These can be used very similar to reactive streams, but (unlike RxJava) are intended to be used with Kotlin and benefit from Kotlin's improvements over Java. This option is especially attractive now that Google has announced that they are focusing on Kotlin for Android development instead of Java.
While this seems to me to be the best option, I have not managed to find any feedback from others about whether it works and if there are side-effects and/or pitfalls to such an implementation. The only thing I found was an open issue on the kotlinx.coroutines repository about the need for providing an example of an application like this. While I'd love to contribute such an example, I don't think I know enough about it to create a good example, and I don't want my production apps to be the guinea pig. I also don't know whether it is better (or proper) to use explicit couroutines with Channel or to use suspend with Flow for this case.
In summary:
Are Kotlin Coroutines and their associated concurrency structures a good way to handle communication between Android Service and Activity?
If yes, which Kotlin type makes more sense to use, Channel or Flow?
Coroutines don't really help with the handoff of data from one software component to another. They help with the processing multiple units of asynchronous work using syntax that appears as if they were synchronous. That's the bottom line for coroutines. They're analogous to async/await syntax in JavaScript. While you might use a coroutine to access data from asynchronous sources, it doesn't give you any primitves to proxy that data on to other components.
LiveData probably works just fine for what you're trying to do. Don't conflate ViewModel with LiveData - they solve different problems. While you're correct that ViewModel should only be accessed by code that deals with UI, that guideline doesn't extend to LiveData. It's perfectly reasonable to expose a LiveData that reflects current data from FirebaseMessagingService that is later picked up by a ViewModel, transformed, and passed on to a view. This LiveData could be a singleton, or obtained via whatever dependency injection infrastructure you choose.
Bear in mind that LiveData is really only supposed to be used for managing changes in state. It's not a "stream" of data that your app can listen to. You will need to make sure that your infrastructure is state-based in order for this to work out well. FCM itself is not state-based, but if you want your views to respond to messages from FCM, you'll need to retain enough context between each message to make sure your UI responds consistently to new messages (or the lack of messages altogether).

Pattern for notifying Activity of a network status code

I have many Activities that have several fragments. Part of the work those fragments do is to make authenticated network calls. It is possible that the token will expire. When that happens, I will see the 401 in the networking layer. What is the preferred method to communicate back to up the stack to whichever fragment initiated the network activity that it needs to initiate the logoff procedure? In other words, when the networking layer gets a 401, I want to communicate that back to the UI that the user needs to be log offeven though many other Activities may have also been invoked since then. This is often done via custom exceptions being handled in the app but I was wondering if there was a specific pattern that was preferred other than that. Something using Live Data perhaps?
You should separate in layers. Each layer should be responsible of a single task. There are many ways to do this, but you could use the MVVM Google approach which consists in:
M (Model): data classes and repositories that persist/retrieve them.
V (View): Activities/Fragments that observe data objects (LiveData) exposed by the VM and also call actions of the VM.
VM (ViewModel): Exposes actions, e.g. login, internally calls a Repository which calls the API (e.g. using Retrofit2), when it receives a result, it updates the data objects observed by the V.
Have a look at:
ViewModel
LiveData
Codelab

Android app architecture with BLE

I am developing an android app with BLE API from android. My app needs to connect to a BLE device, and remain connected as long as it is in range and turned on. I need to read data from it, and write data to it.
I am trying to follow the MVP architecture pattern, not strictly since activities are the starting point. But anyway, I wanted to know where should I put the interaction with Bluetooth? I am searching for answers for the following questions. I have searched StackOverflow, but couldn't find what I was looking for.
Should it be in a service bounded to the UI just like in googlesample ble app ? But, I think that would break the whole mvp architecture.
Should it be a bounded service at all ? If no, what would be the best way to implement the service? In my mind, if it's not bounded to the view, and there is a callback from the background service to display something on the UI, there is a possibility of undefined behavior.
Who should initiate the Bluetooth interaction ? The application class or some activity ?
I am looking for mainly architectural guidance, and best way to go about developing this app.
Since you have the requirement that the Bluetooth connection should keep working in the background, you should have a Foreground Service somewhere running in your app process. This will make sure your app process will be kept alive, but requires an icon to be displayed in the phone/tablet's top bar.
Whether you actually put your BLE code in this service class or not doesn't matter for the functionality.
There are of course many ways to achieve good architecture but here is my approach.
My approach would be to have a singleton class that handles all your BLE scanning, connections and GATT interactions (from now on called Manager). Since some BLE operations needs an Android Context, a good way is to use the Application context as context. Either follow Static way to get 'Context' on Android? to be able to fetch that context at any time or subclass the Application class and from its onCreate call some initialization method in your Manager and pass the context. Now you can keep all BLE functionality completely separated from Android Service/Activity/Application stuff. I don't really see the point in using bounded services etc. as long as you keep everything in the same process.
To implement a scan functionality, you can have a method in your Manager that creates Scanner objects. Write the Scanner class as a wrapper to Android's BLE scanner and expose methods to start/stop scan. When you create a Scanner that method should also take an interface as argument used for callbacks (device reports and errors). This class can now be used in for example an Activity. Just make sure that the scanner gets stopped in the Activity's onStop method to avoid leakage of objects.
There are several reasons for having a wrapped custom Scanner object instead of using Android's BLE scan API directly in the Activity. First you can apply the appropriate filtering and processing of advertising packets so it handles your type of peripheral and can show high level parameters (decoded from advertising data) in your custom advertising report callback. The manager should also listen to broadcasts when Bluetooth gets started/stopped/restarted and keep track of all started Scanners so the Scanners are restarted seamlessly when Bluetooth restarts (if you want this functionality). You may also want to keep track of timestamps of all scan starts/stops so you can workaround the new restrictions in Nougat that limits it to 5 scans per 30 seconds.
Use a similar approach when you want to connect to your peripherals. You can for example let the Manager create Device objects which have methods to start/stop the connection and have a callback interface to report events. For each supported feature (for example read some remote value) you should expose a method which starts the requests and have a callback which is called when the result arrives. Then your Manager and Device class takes care of the GATT stuff (including enqueuing all your GATT requests so you only have one outstanding GATT operation at a time). Just make sure you can always abort or ignore the result when you don't want the result, for example if an Activity's onStop or onDestroy method is called.
Since you probably want to reconnect automatically in case the device gets disconnected, you should use the autoConnect flag and set it to true when establishing the connection, which assures this. Again, the Manager should keep track of all active Device objects and automatically recreate the BluetoothGatt object when Bluetooth is restarted.
To be able to display different kind of UI stuff, like for example automatically show a warning message in your Activity when Bluetooth is turned off and remove it when Bluetooth is turned on, you should be able to register Listeners to your Manager. Have a method in your Manager for registering/unregistering a listener (which is really just a Callback) object, keep track of all the listeners and when Bluetooth state change happens, call all listeners. Then in your Activity's onStart you register a listener and in onStop you unregister it. You can have a similar approach for your Device's BLE notifications, where applicable.
What's left is how you deal with different Threads. As you might know most BLE callbacks from Android's API happen on Binder threads, so you may not update the UI from them. If you otherwise in your app don't use anything other than the main thread, you can for example post all invocations of callbacks in the Manager to the main thread, or maybe move to the main thread directly when the callback from Android's BLE stack arrives (but then be aware of things like https://bugs.chromium.org/p/chromium/issues/detail?id=647673). Just make sure you never touch the same variables from different threads.
Also if you target API 23 or higher you need UI code to let the user give permission to Location to be able to start scan. I suggest you implement this in your UI code and not in the Manager, or implement some "wrapper" or helper method in the Manager to do this.
RxCentralBle provides a paradigm for use in an app. The library design clearly shows the structure of the library. In short, RxCentralBle provides reactive interfaces for the primary Bluetooth LE actions:
BluetoothDetector - detect phone Bluetooth State
Scanner - scan for peripherals
ConnectionManager - connect to a peripheral
PeripheralManager - queue operations to communicate with a peripheral
It's recommended to subscribe to these interfaces on a background thread and ensure resources and subscriptions live at the application scope i.e. member variables of your Application class. As long as your Application is running, all Bluetooth LE resources will remain alive and active.
Check out RxCentralBle's Wiki and sample app to learn more.

Is it a good idea to use Service as Presenter in MVP context

Short stated my question is: in MVP architecture is it a good idea to use a Service as
Presenter to control a Model implemented as Service ?
Alternative question: Is using a Service to control another Service a good idea ?
The context:
I am writing an app that communicates with a bluetooth sensor.
The app has a Service
(aka BluetoothService) that makes the connection and manages the communication with the sensor.
The app has several Fragments but just few of them are related to the operations that
the Bluetooth sensor does. A user should be able to start an operation, navigates to different
fragments and later watches the results of the operation(s) done by the sensor.
My purpose:
I want to write a component (aka BluetoothController) that makes the links
between the sensor (represented in my app by BluetoothService) and the rest of
the app. The BluetoothController contains Objects that described what kind of
operation has to be done by the sensor (only one operation, serial operations,
type of the operation, ...), so BluetoothController 's purpose is to let
the operations be independant to Bluetooth sensor and then be able to test the app
with a mock bluetooth class. I see BluetoothService as a model and
BluetoothController as a presenter, am I wrong ?
Why a Service:
Because it does not die if the user navigates between fragments
Because it is accessible through the whole app via bindService
Because bindService is the only entry point, I guess I can control that just
one operation is done at a time
Because I see Service as an active component, so it can keep on receiving data even if there is nothing bound to it
This service would be both started and bind (like a music player):
to be able to keep on running even if no components are bound to it,
to ease communication
All services would be in the application process to let communication be done
without binder but rather
method call.
Any suggestion would be highly appreciate , thanks in advance
Why not something else:
RetainedFragment are (for me) just container
pojo presenter are just gateway between views and models, they should die if
they are not attached to a view.
Conclusion
Am I wrong? Do you see difficulties in this architecture? Are there other Android
components that suits my purpose better?
Any suggestions would be highly appreciated, thank you in advances

Categories

Resources