I am building a bluetooth app that tracks temperatures in the background assuming the app has not been destroyed. I noticed that in Android Oreo we have background execution limits. I need to know if I am missing anything from my project. Here is how I have the project laid out.
I have a MainActivity that has a bluetooth class BluetoothObject that takes care of communication between the main activity, BluetoothGattCallback() class, and my local Realm database.
I have now implemented a Service() in BluetoothObject, that is a bridge between the BluetoothObject and my Realm database. So far everything seems to work. I used this example to set everything up.
Since this is a bound service, do I need to call anything else to keep the service alive in the background? After I set it up, I bind the service by calling:
val intent = Intent(context, BoundService::class.java)
context.bindService(intent, myConnection, Context.BIND_AUTO_CREATE)
I also have the service set in my manifest file as instructed by the example.
The issue I am seeing is the bluetooth connection stays connected while the app is open and if the screen is asleep. I have issues is when my app goes to the back of the app stack and then the phone is asleep. The connection maybe last an hour. What can I do to keep this connection alive? Is there any permissions I need to enable? Is there something in Android 8+ that causes issues?
There is no issue. That limitation was put specifically to kill background services that could be heavy on battery (ongoing sockets, blue tooth connections, etc.) and not directly visible to the user.
If you want your service to run unstopped, You will need to settle for Foreground service with a notification.
Related
My Android app activity binds to a service, which connects to a BLE peripheral and receives data. It does this until the user presses a button on the activity to disconnect from the peripheral and stop the service.
Sometimes after running with the screen locked for about ~45 minutes+ the activity and service are terminated. My conclusion was that Android 8.1 was more aggressive than previous operating systems, so I changed the background service to a foreground service, and made sure that once the peripheral is connected I stop scanning.
This didn't work, and every now and then my app is killed in the background, and I don't think it is an uncaught exception. I have read the Android docs on Services and the Application Lifecycle and have added some debugging logs into lifecycle callbacks, which hasn't helped. I have observed this behaviour on Huawei Y5 and Nokia 8 running Android 8.1 - I don't remember it being an issue on an older phone which I no longer have.
I have a few questions about behaviour that aren't clearly documented that might help me figure out this issue. Thanks for your help!
1. If an activity is killed in the background and it is bound to a service, will that kill the service?
2. If a service is killed in the background, will that kill my activity
3. If there are multiple services running and one consumes too many resources, does the OS kill everything, or just the misbehaving service?
4. What sort of things makes an activity or service a target for the OS? Holding on to wakelocks permanently? BLE scanning? Receiving too many BLE packets? Uploading too much data? Any insight here about what might be happening under the hood is appreciated.
5. Does having the phone on charge prevent the OS from killing apps? I believe it occurs in my case regardless.
There are several reasons for Android to kill.your activity. Therefore it is not a good idea to setup you bluetooth in an activity. Set it up in a seperate class or in your Application class and use other ways to send data to your activity, e.g. broadcasting. That way it will keep working even if your Activity is killed or recreated.
Is your application really being killed or is it just your Activiry that is killed?
I am developing an application in Android that connects to a Bluetooth device. On occasion, an alarm created by the alarm manager goes off and is supposed to send information to the connected Bluetooth device. My question is, what is the best way to make this connection so that I can communicate with the device when the activity has been stopped (app is closed). I have read about intent services, foreground services, remote messenger services, and have not found any source that says the best way to make a service that won't end when the application is closed to host Bluetooth.
create your service class extend service and bluetoothadapter init in yourservice oncreate()
Foreground Service
First of all I suggest using a foreground service.
The service runs indefinitely and the app will be recreated each time it is killed (by user or by system).
In addition foreground services are also excluded from Oreos background execution limits.
Check out this post for a detailed description and test of Android service's lifecycle. Please also be aware that testing the lifecycle of services can be quite a struggle. Debugging tools usually loose connection to a service once the app is swiped off of recent used apps list or killed otherwise.
Service lifecycle
Once you set up the foreground service you should make use of service's lifecycle hooks as pointed out by Yongho to keep a reference to peripherals.
For example you could create and assign BluetoothScannerCallback to an instance variable in OnCreate() like so:
OnCreate() {
_scannerCallback = CreateScannerCallback();
}
This way you'll be notified about connection losses. Also use Androids Bluetooth Default Adapter inside the service in order to keep connections to Bluetooth devices alive when the host application is moved to background or killed (and recreated).
You should also deinitialize all references in OnDestroy().
Where I'm Currently At:
I would like to be able to run Bluetooth in my app in the background on android. I have read various guides and understand the idea of creating an intent service (something like android.app.IntentService and extending it, overwriting the onHandleIntent with your desired behaviour) however, I don't understand how that would interract with my existing behaviour? So for example, I currently call:
...
var bluetoothManager = utils.ad.getApplicationContext().getSystemService(android.content.Context.BLUETOOTH_SERVICE);
adapter = bluetoothManager.getAdapter();
adapter.startLeScan(Bluetooth._scanCallback)
...
(this is in JavaScript, using the nativescript runtime, so don't worry about it looking a bit wierd.)
Where I'm trying to get to:
I would like to being able to scan for and reconnect to paired devices in the background and recieve (store in SQLite) GATT Characteristic updates.
Question:
So how do I create this functionality in the type of service that can be run in the background as described above?
The Bluetooth LE Gatt APIs are built upon Android's Binder mechanism, which means it will only work during the app process is alive. You must make sure your app process isn't killed by the system. The easiest way to do that is to have a foreground service running (not an intent service). The only important thing is that the foreground service is alive and running, your service class itself doesn't have to do anything. But I guess the easiest way is to put all your BLE code inside that service. See https://developer.android.com/guide/components/services.html#Foreground.
I am writing an app that connects to a Bluetooth device, continuously receives data from it, and stores in local db. Certain data received requires system alert to pop up. There is a main activity which just displays the status of connection and data received. It all works just fine so far, including the popups.
Since the app requires to be run in background I have implemented a "bluetooth connection" service that manages the BT connectivity, and displays ongoing notification in order to avoid being killed. For coding clarity reasons I would like separate background service to collect all data, and log it (instead of having BT service do all the work). I also prefer loose coupling between my app components, so am using GreenRobot's event bus for all IPC. As a result my BT connection service is completely unaware of any data collection/logging code - it just dispatches a message to event bus and I'd like to keep it that way.
Now I'd like to have my data collection/logging code to be run as another background service. Is there a way to ensure it runs as long as BT connection service is running? And without displaying yet another ongoing notification or tightly coupling the code between two services?
You could let your class extend service so in this case you dont have to make a notification for it. Basically it keep running in the background without the need of displaying notification on the status bar. Make sure before you exit your app to stopservice() otherwise it will keep running until the device restarted or in somehow the user force stop your app from application manager inside of the settings.
I am trying to develop an application which will require a service to
run in the background. I am relatively new to android programming,
and after reading many posts, blogs, how-to's and books on creating
and managing services, I am still pretty confused about which model I
should try to use.
First, let me present (in general) the application requirements: I
need an application which will spawn a background process (service?)
which will connect to a bluetooth device. The bluetooth device is
designed to deliver data to the android device. The issue is that the
data could come in at any moment, so the bluetooth connection has to
stay active. Note that the application is a VERY SPECIFIC app and is
NOT intended for public use. I do understand the arguments for not
having background apps running all the time, but please understand
that this is a very specific application for a very specific client.
Now, in general, I think the program flow would be to start the
application (and launch a UI activity). Then I need to configure and
connect to the bluetooth device. At this point, the user should be
able to do other things - make phone calls, check their email, etc.,
while the bluetooth connection is still active and potentially
receiving data. If data comes in, a notification is fired, etc.
So here are my questions and concerns:
If I start an app (which spawns a UI activity and ultimately my
bluetooth connection service) but the app is killed, apparently, the
service handling the bluetooth connection is killed as well. How can
I keep that alive? I read that Service.setForeground() was
depricated, but even if I were to set it to the foreground, if the app
is killed, the service is killed as well. I need to have it run in
the background with as high of a priority as possible (again, I do
understand that this is considered "bad form", but this is a specific
app and this functionality has been requested by the client).
If I started the app (and the service, etc.), but the user, say,
answers a phone call, the app is put into the background. However,
let's say the user goes back to the home screen and starts a DIFFERENT
instance of the app, i.e., he doesn't hold down the home key to select
the already running app from the task manager but starts a completely
new one. If the service handling the bluetooth connection is still
running, how will this new instance behave? i.e., how can I get it to
connect to the bluetooth service which is ALREADY running in the FIRST
instance of the app instead of this new instance? Do I have to use
some form of a Remote service instead of a local service? This is
where I'm a little confused by things as it seems remote services and
defining an AIDL seems to create a lot of extra overhead, and since
I'm already creating a lot of overhead with the service running in the
background all the time, I want to keep that as small as possible.
How can I insure I am connecting to the same service already running?
1)
The service does not depend on an Activity. You can have it running on the background until you call stopSelf().
You can have a BroadcastReceiver that listens to the android.intent.action.BOOT_COMPLETED so your service is started when the phone is turned on.
2)
Your Activity should bind to the service. And get the info from it.
Check this question.