When I started working on a mobile application using Android SDK, I wanted to make a BluetoothService class, which would allow me to connect to a paired device and communicate with it by injecting the service whenever I need to.
However, when I tried to implement the Service, I realised that Android BluetoothAdapter depends on an Activity (aka. an active view). So I gave up the idea of having a Service and implemented the Bluetooth directly in the view.
Although it worked, I still had a problem.
Basically, my application was a remote that could be used to control a specific joint/stepper motor of an articulated arm at a time.
Whenever the user wanted to switch to another joint, they either could use the upper right menu, or press the picture at the top (depicting a picture of the arm) to get to another view, where they could press on the part they wanted to control (directly on the picture). It would then return them to the main activity with the arrow buttons.
However, the fact that the application is switching to another activity means that the previous one was destroyed. As such, it happened that the application would temporarily lose the Bluetooth connection with the other device, whereas using an injectable BluetoothService would have allowed my application to carry it over different activities.
Why do I need an Activity to use BluetoothAdapter?
Permissions and discovery require an activity because they require user input. The rest of the Bluetooth APIs should, on the whole, not require an activity. In particular, once you get a BluetoothDevice, the actual Bluetooth I/O should be able to be done without an activity.
In your case, it is not clear that you really need to be doing this work in the background, so a service may not be required. Either:
Use a single activity for all of this work, using fragments or something to handle the work being triggered by the action bar item; or
Have the Bluetooth communications be managed by some singleton, perhaps using a variant on the repository pattern, that lives outside of either activity
Related
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.
I work on a project that has several developers.
We work on one rather large app.
Every developer has several activities that can be seen as sub-apps of the whole main-app.
I do realize, that this may not be the best design, but it exists and we have to handle it somehow.
Now the main issue is, that we need a master, that is always active and checks I/Os etc and that can give out status changes to every sub-app/activity. Something like "we just lost internet connection" etc.
Right now, that master is a singleton, that is first instantiated by the launcher activity and that every activity/sub-app can register to by passing the appropriate interfaces depending on what updates the activity would like to receive.
This is working, however it doesn’t feel right, because the singleton needs context to access system resources to determine system stati like internet or gps. Should the singleton be killed by OS, than a simple "getInstance" wouldn’t do much good, because the singleton would somehow need to acquire a context. I've read about extending the Application class and creating a static member context there, but this variable had to be volatile AND its possible that it returns null if the entire app is in some restart-after-crash/kill state. It doesn’t feel safe.
In addition, there should also be a possibility that the master somehow opens a user-dialog to display warnings etc to the user. Those warnings should look the same across the entire app and no dev should have to worry about when or why it suddenly pops up. Right now, those messages appear as custom toasts that overlay everything. Of course they require context and if the app is about to close there could be a problem.
All in all, that’s the mess we are in and I’m looking for a solution.
So how do I create a safe master object or activity (or even service ?!) that can pass info to different activities and post warnings etc (and Maybe even has the ability to close activities or at least order them to close themselves without the need to register a can_close interface).
It should be that safe, that if after a crash android only restarts the activity that was active it somehow manages to also be restarted or at least have/give the same info as before.
Every idea is welcome but total overhauls of the app are just not possible (lack of time and manpower)
Here are a few ideas:
Create a Service component for all the monitoring you need to do.
If I understand correctly, this service will be required only if
some of the activities are running. So you can make it a bound
service. Let all activities bind to this service when they start
and unbind when they close. The service will be started when the
first activity binds.
Create a base class for all your activities. You can write all the common code here. e.g. the code to bind to and exchange messages
with the master service. This class can also contain utility methods
for notifying user etc. So all activities will use the same method
for notification.
For user notifications, you could either use Status Bar Notification or create a Fragment which can capture, aggregate
and display the notifications. You can have a common menu item
implemented in the base Activity class to show/hide this Fragment.
If you use Status Bar Notification, make sure you use one aggregated
notification for your app. Otherwise, the different activities might
create a clutter in the status bar.
I guess that one solution would be to create a service that serve as the master.
You will have to make it run independently of the different activities (but don't forget to manage own to shut it down neatly if the app is no longer used, you don't want to kill your clients battery).
A service can't act on the interface though, so you will probably need to broadcast messages to the activities to order them to open a dialog.
A final thought : Toasts are ok but popup that block the interface are very bad, especially on a mobile device.
I'm working on an Android application interacting with Arduino. I'm trying to manage multiple activities, each one being responsible for controlling a specific part of the Arduino board.
Unfortunately, tutorials on the web use only one activity. So I don't know how to proceed for keeping the connection with Arduino alive while navigating to a new Activity or for closing it properly and then re-open it on the new Activity.
Any idea?
You could use a Service to connect to Arduino and to keep that connection open. Your Activities can then talk to the Service, being started, stopped, switched, etc.
EDIT: How this can be done is already handled by another question/answer:
Long running ADK Accessory (Service?)
I haven't used Arduino with Java before, but you might want to follow a Singleton pattern. Using a Singleton pattern, whatever objects you are using to connect to it can be accessed from multiple activities and multiple threads.
Using a Singleton will only alleviate your problem though. You still need to figure out how to close/reopen it.
Also, it is important you know how the Activity Lifecycle works. If a user receives a phone call, the screen turns off, or the orientation of the screen changes it will destroy your activity and recreate it. You'll have to handle how you're going to save and restore where you were. This will most likely mean you have to close/reopen the connection.
I am creating a project which connects to an embedded Bluetooth chip. Currently I have it set up with a separate application class which controls all the bluetooth functionality.
My program initialized with a main menu that has 9 buttons. In the main screen I create the connection to the Bluetooth device. Each button brings me to a separate Activity. Each activity needs to receive different pieces of data from the Bluetooth chip.
My question to you all is, would it make sense for me to use a service instead of an application? From what I understand of a service, it is used because there is always something running in the background. However in this case nothing needs to be running in the background ( unless keeping the connection with the Bluetooth device counts), data is only sent/received when an Activity asks for it.
Or, am I completely off track and shouldn't use either? Just a simple class to act as my data container which can be passed through intents? I know this will work, but am very new to Android and intents seem to be a bit messy. I would rather not use intents if I didn't have to.
I'm also building up a bluetooth connection, and i put the whole communication stuff in a service and bind to this service with every activity that needs to use the connection. This works pretty well for me. You might want to choose this way too.
Actually i earlier realised a way holding the connection in the application, but now i prefer the service way, because i'm using the application for global states.
Using service also reduces the need of intents to a very small amount :)
In your case a static property for the bluetooth connection would be the most pragmatic solution
First I'm sorry for my english that is not so good :).
I am facing a problem to develop my app.
That is a general architecture scheme of my solution.
http://i.stack.imgur.com/ooTmE.png
To be quick, the app has to decode code bare but with two possible ways:
using exernal device (The constructor provides a sdk containing an android Service to communicate with the device),
use the camera of the mobile using the library Zxing which is possible to manage it with intent.
The goal of my own service is to manage some business code and make transparent the choice of the tool for the user.
I believed that was a good solution but I wanted to implement it and I had different problems.
My main trouble is that I cannot execute StartActivityForResult inside the service.
Do somebody have any suggestions for my problem whether a change in the architecture or a solution for the main problem?
#Laurent' : You have totaly right my service acts as an API adapter.
I will try to make the expected behaviour more clear.
I have an app that needs to recognize (real) objects which have QR codes on their top. This recognition action will be done several times by the user during the life of the app.
The user chooses to launch the recognition by clicking on a button (or otherwise but he knows that the recogntion will start). So no notification is needed.
The thing is he doesn't choose the way to do the recogniton. It is why, as you said, I implement an adapter.
The adapter chooses between :
Camera mobile or external device. The first is an activity coming from the Zxing library. The second one is a service that manages the external device. This service provides an interface to get back result.
One more thing, I need that my whole implementation (adapter and co) can be re-used by other apps that will also need to do recognition.
So my thought was to implement a service as an adapter to answer my two conditions (make transparent the choice for the user - and make the recognition available for other apps).
I hope you understand my problematic.
Given your architecture, your MyOwnService must act as an API adapter : it should provide a unified scanning API and address each external service specificities transparently.
Your expected behaviour is not clear enough to provide a solution that suits your needs but here are a few remarks that can be of some help.
Passive scanning:
Even if there are some workarounds : no activity should be launched from a service (not directly). Never. Bad. Services are background stuff, the most they will be permitted is to hint users with Notifications (this is point 2 of Justin excellent answer).
As a consequence there's nothing as a 'popup Activities' (and that's good!). If you need to continuously scan for barcodes, even when your activity is not run, then the only way to warn users is by using status bar notification.
Active scanning:
Inside your own activity you can bind to your wrapper service and make it start scanning for codebars. When it finds one it has to message your activity. Your Activity message handler has complete access to the UI to inform the user of your findings.
You selected Active Scanning in your edit, your problem is therefore to find a way for your service to actively notify your main application (the one that started the active scanning) that a new item has been scanned successfully.
You do NOT do this by starting a new activity (remember: this is bad) but you can bind to a service and/or use Messages between the wrapper service and the application.
I advice you take the time to read (and more time to comprehend) this android developer article on BoundServices and especially the part about Messengers.
A full example of Two Way Messaging between a Service and an Activity can be found in the following android examples : Service & Activity
Warning: designing robust, full blown AIDL-based services is a tough job.
Two ways you could solve this problem.
1) Have MyOwnService do a callback into MainActivity telling it to launch your ScanActivity.
- This is a better approach if MyOwnService's task is only going to be running while MainActivity is running and if the user would expect the ScanActivity to come up automatically.
2) Have MyOwnService create a notification that will let the user access the ScanActivity.
- This is a better approach if MyOwnService's task might be running longer than the life span of MainActivity. That way, you can let the user know, unobstrusively, that they might want to access the ScanActivity.
So finally I changed my architecture.
I make the choice to delete myOwnService and to create an intermediate activity that will be my API Adaptater.
This activity will have a dialog.theme to look like a dialog box indicating that a recognition is under execution.
If the recognition uses the external device this activity will stay at the foreground otherwise the camera activity will start (Being managed by the intermediate activity).
Thank to that I can manage my result from the intermediate activity and do not have an android strange architecture, keeping my business code for the recognition outside my main app.
Service was not the good choice.
Thanks a lot for you help and your time.