I'm trying to build an android service that continues the bluetooth low energy scan from my jetpack compose app that interacts with a ble beacon. My goal now is simply to get my foreground service started once I put my app in the background. My code compiles, the log statements that keep track of the process shows up normally in my logcat, but the service process ends the moment it is started and the notification never appears on the status bar.
Here is my bluetooth service class code
@AndroidEntryPoint
class BluetoothScanService : Service() {
@Inject lateinit var bluetoothUtils: BluetoothUtils
@Inject lateinit var sharedDataManager: SharedDataManager
@Inject lateinit var bleScanCallback: BleScanCallback
override fun onCreate() {
super.onCreate()
// Initialize your BluetoothUtils, SharedDataManager, and ScanCallback here
Log.i("foreground", "Inside onCreate in Bluetooth Service")
val notification = createForegroundNotification()
startForeground(1, notification)
Log.i("foreground", "BluetoothUtils: $bluetoothUtils")
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null) {
Log.e("foreground", "Received null intent in onStartCommand")
return START_NOT_STICKY // or return an appropriate value
}
Log.i("foreground", "Inside onStartCommand in Bluetooth Service")
// Start the Bluetooth scan in the foreground service
bluetoothUtils.startScanning(bleScanCallback)
return START_NOT_STICKY
}
private fun createForegroundNotification(): Notification {
val channelId = "BluetoothScanChannel"
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Create notification channel for Android 8.0 and above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId,
"Bluetooth Scan",
NotificationManager.IMPORTANCE_DEFAULT
)
notificationManager.createNotificationChannel(channel)
}
// Create the notification
val notification = NotificationCompat.Builder(this, channelId)
.setContentTitle("Bluetooth Scanning")
.setContentText("Bluetooth scanning is running in the background.")
//.setSmallIcon(R.drawable.ic_bluetooth)
.build()
return notification
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
}
and this is how I call the service in my onPause() and onResume() from my MainActivity (I have only one activity, because I am using Jetpack compose. Every screen in my app is a composable).
override fun onPause(){
super.onPause()
Log.i("foreground", "Inside onPause in MainActivity")
val intent = Intent(this, BluetoothScanService::class.java)
Log.i("foreground", "the intent ${intent}")
startService(intent)
}
override fun onResume() {
super.onResume()
Log.i("foreground", "Inside onResume in MainActivity")
val intent = Intent(this, BluetoothScanService::class.java)
stopService(intent)
}
And this is my logcat results
2025-01-21 13:49:32.544 32677-32677 foreground com.myApp.bleApp I Inside onPause in MainActivity
2025-01-21 13:49:32.545 32677-32677 foreground com.myApp.bleApp I the intent Intent { cmp=com.myApp.bleApp/.common.foregroundServices.BluetoothScanService }
2025-01-21 13:49:32.590 32677-32677 foreground com.myApp.bleApp I Inside onCreate in Bluetooth Service
2025-01-21 13:49:32.691 32677-32677 foreground com.myApp.bleApp I BluetoothUtils: com.myApp.bleApp.hardware.bluetooth.BluetoothUtils@7da3008
2025-01-21 13:49:32.693 32677-32677 foreground com.myApp.bleApp I Inside onStartCommand in Bluetooth Service
---------------------------- PROCESS ENDED (32677) for package com.myApp.bleApp ----------------------------
If I use return START_STICKY instead of return START_NOT_STICKY, the process still ends but it is restarted with a null intent and the notification appears in my status bar. These are my logcat results
2025-01-21 13:51:45.677 1960-1960 foreground com.myApp.bleApp I Inside onPause in MainActivity
2025-01-21 13:51:45.678 1960-1960 foreground com.myApp.bleApp I the intent Intent { cmp=com.myApp.bleApp/.common.foregroundServices.BluetoothScanService }
2025-01-21 13:51:45.739 1960-1960 foreground com.myApp.bleApp I Inside onCreate in Bluetooth Service
2025-01-21 13:51:45.809 1960-1960 foreground com.myApp.bleApp I BluetoothUtils: com.myApp.bleApp.hardware.bluetooth.BluetoothUtils@eaa3f16
2025-01-21 13:51:45.811 1960-1960 foreground com.myApp.bleApp I Inside onStartCommand in Bluetooth Service
---------------------------- PROCESS ENDED (1960) for package com.myApp.bleApp ----------------------------
---------------------------- PROCESS STARTED (2496) for package com.myApp.bleApp ----------------------------
2025-01-21 13:51:49.731 2496-2496 foreground com.myApp.bleApp I Inside onCreate in Bluetooth Service
2025-01-21 13:51:49.741 2496-2496 foreground com.myApp.bleApp I BluetoothUtils: com.myApp.bleApp.hardware.bluetooth.BluetoothUtils@861bce1
2025-01-21 13:51:49.742 2496-2496 foreground com.myApp.bleApp E Received null intent in onStartCommand
This is the error I get when the process ends
FATAL EXCEPTION: main Process: com.myApp.bleApp, PID: 7298 java.lang.StackOverflowError: stack size 8188KB at com.myapp.bleApp.hardware.bluetooth.bleScanner.BleScanCallback.onScanFailed(BleScanCallback.kt:237)
And this is where the error is happening in my bleScanCallback class at onScanFailed(errorCode)
override fun onScanFailed(errorCode: Int) {
super.onScanFailed(errorCode)
// Handle scan failure
onScanFailed(errorCode)
}
The only thing i want to happen right now is that the service stays alive when the app is in the background and I want to see the notification appear in the status bar. How can I solve this?
This is very meta! The issue is that this function is calling itself recursively, which causes the StackOverflowError.
override fun onScanFailed(errorCode: Int) {
super.onScanFailed(errorCode)
// Handle scan failure
onScanFailed(errorCode) // Do you really want to call recursively?
}