I have a BLE android application and as usual I am using BluetoothGattCallback to receive data from BLE device periodically. However, even if I kill my application,onCharacteristicChanged method of BluetoothGattCallback keeps triggering and Android studio shows that app is still running.
I want that all app processes should be killed and onCharacteristicChanged should not be triggered after that.
If your app is still running then per definition it is not killed. Usually you never destroy an app process, but let the system do so when you have no running components anymore. To correctly shut down your Bluetooth connections when you are done, call close() on the BluetoothGatt objects you have. When you are "done" is up to you, but for example in an Activity's onDestroy if the connection is "bound" to an Activity.
Related
I have written BluetoothGattCallback in my activity. I also have a foreground service running to capture user location.
When I kill my app, I can see advertisement packets from Bluetooth Low Energy keeps receiving in onCharacteristicChanged.
But when I removed foreground service, as soon as I kill the app, advertisement packets from Bluetooth Low Energy stops receiving in onCharacteristicChanged (which is desired state).
How can I stop advertisement packets from Bluetooth Low Energy in onCharacteristicChanged when I kill app?
I think your definition of "kill app" really means "destroy the running activity", which is not the same thing as "killing the app process".
The Bluetooth API is completely separate from the Activity logic. Unless you actively do something to stop the notifications from arriving in your app process, and unless the Bluetooth connection geats teared down, they will keep coming until the app process is killed.
If you want the Bluetooth connection to stop when you destroy your Activity, you need to have some logic in the onDestroy method in your Activity (or in the onDestroy method of a service that your Activity is bound to) that for example makes sure the close method is called on your BluetoothGatt object.
Last thing, what you get in onCharacteristicChanged is notifications or indications. Not advertising packets. Advertising packets is what you get when you perform a scan.
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?
In my app, a Service is started in the background to handle BLE communication with a BLE device. I have an Activity (StartActivity) on start of the app which searches the BLE device and when it found it, it starts the Service (BleService), hands the found Device to it and then binds to it to receive Broadcasts from BleService.
BleService establishes the BLE connection, sets notifiers on different characteristics and reads them. As it got all the information it initially needs, a Broadcast is sent.
This Broadcast causes StartActivity to switch to another Activity (MainActivity), which then binds again to BleService and reacts to BleService's Broadcasts.
So far, so good.
When I press the back button while in MainActivity, the app 'closes'. Now, when I restart the app (either by clicking on its icon or in the recent app list), the app gets back into StartActivity and can't connect to the BLE device. As the LED on my BLE device is constantly signalling me, it's connected, I think the first BleService is still running and connected to the BLE device.
I checked this by adding a Log output to BleService's onDestroy() method and yes, onDestroy() isn't called. It is called, when I close my app through the recent app list.
What should I do when closing my app through the use of the back button?
EDIT: So I want to destillate my problem out of my question:
When I close my app on pressing the back button in MainActivity and then start it through the recent app list or via its icon again, I get stuck in StartActivity. This is, because StartActivity can't find the BLE device, as it is still connected to the still running BleService.
How can I avoid this?
I am not sure what you want to have happen when "back" is pressed, but you can take a look at this answer to help you determine if the service is running or not and take appropriate action.
If your client and server code is part of the same .apk and you are binding to the service with a concrete Intent (one that specifies the exact service class), then you can simply have your service set a global variable when it is running that your client can check.
We deliberately don't have an API to check whether a service is running because, nearly without fail, when you want to do something like that you end up with race conditions in your code.
An Android Service is meant to remain running even when its parent application terminates. This is an important function to be able to execute any critical operations even when the application crashes/closes/gets killed...
For you, this simply means that you have to close your service upon quitting your app, at least if this is what you intend to do. Doing this is very simple:
stopService(new Intent(ActivityName.this, ServiceClassName.class));
If you are starting your Service via Context.startService() then it must be stopped via Context.stopService() or the service itself calling stopSelf(). Binding/unbinding to the service will only stop it if the binding was how the Service was started in the first place (e.g. not using startService()).
It always seemed some sort of black magic the way other apps keeps their services always running, but mine gets killed by the system every time.
My app should keep a TCP socket open to the server and send/receive data when it becomes available, so it has to stay always on.
This is what I have tried so far:
1) Running the service in another process using this line (also with an additional line stopWithTask):
android:process="package.name.custom_process_name"
android:stopWithTask="false"
2) Restarting the service when these methods get called:
onTaskRemoved()
onDestroy()
3) Add return START_STICKY to onStartCommand() method
4) Check if the service is still running when these events happen:
android.net.wifi.WIFI_STATE_CHANGED
android.net.conn.CONNECTIVITY_CHANGE
- Here I am stopping the socket connection to the server if the device does not have internet connection anymore and reopening it when it gets a connection.
Yet, my service always gets randomly killed (sometimes after few hours, sometimes after few days) by the system and doesn't restart automatically until I reopen the app.
How does other apps, say chat apps for example, keep their services available all the time?
P.S.: Having a persistent notification would be the least of options.
Override onDestroy() in your service, whenever your service destroys create Alarm using AlarmManager. When alarm trigger start your service again.
Second way is not recommended or proper way but create a separate service AlwaysAliveService which will do nothing but will remain available in android system.
I stop getting onCharacteristicChanged after exiting the app and restarting it.
Here are the steps I did pairing to a ble device.
I have a service that contains the ble logic and persist the bluetoothGatth obj, I perform a blueToothGatt.connect here on app launch.
Once I get onConnectionStateChange with STATE_CONNECTED, I call blueToothGatt.discover
On the onServicesDiscovered callback, I will fetch and persist the services and characteristics that I care about. Then I will call blueToothGatt.setCharacteristicNotification and write to descriptor to enable notification.
Now I perform a write and then I will get callback for onCharacteristicChange just fine.
After this, say I exit the app (device is still paired). The onDestroy of the last activity, my ble device service gets unbind...in which I will perform close on unbind callback and call selfstop to stop the service. Now if I relaunch the app. I will do the same steps 1-4, however this time around onCharacteristicChange does not get call, also I tried disconnect before close...but that didn't help
(One thing that I do notice is that if the device is left unpaired/disconnected upon relaunch then the issue occurs, however if I power of the BLE device off and turn it back on before restarting the app, then I get the callback onCharacteristicChanged just fine. This seems like the device is holding onto some setting that prevents onCharacteristics to get call.)
Any insights to this will be greatly appreciated. Thanks!
I found the solution to this. Basically the bluettooth caching the last handle, so discover services is never triggered. You will need to clear the device cache after connect.
How to programmatically force bluetooth low energy service discovery on Android without using cache