First of all, I looked at these;
I have a streaming application used by almost a million people. I'm using foreground service for the player. I didn't implement MediaSession
yet. I have a 99.95% crash-free sessions.
So this app works on all versions but I started getting crash reports(ANR) with android 9. This crash occurs only Samsung
phones, especially s9, s9+, s10, s10+, note9
models.
I tried these,
startForeground()
method in onCreate()
Service.startForeground()
before Context.stopService()
I read some comments from developers of Google, they said it's just Intended Behavior
. I wonder is it occurred by Samsung's system or Android OS. Does anyone have an opinion about this? How can I fix this?
I was waiting my crash report to share the solution. I didn't get any crash or ANR almost 20 days. I want to share my solution. It can help those who encounter this problem.
In onCreate()
method
onCreate()
. Official doc Service.startForeground()
method after Context.startForegroundService()
method. In my prepareAndStartForeground()
method.
Note: I don't know why but ContextCompat.startForegroundService() doesn't work properly.
For this reason, I've added manually same function to my service class instead of calling ContextCompat.startForegroundService()
private fun startForegroundService(intent: Intent) {
if (Build.VERSION.SDK_INT >= 26) {
context.startForegroundService(intent)
} else {
// Pre-O behavior.
context.startService(intent)
}
}
prepareAndStartForeground()
method
private fun prepareAndStartForeground() {
try {
val intent = Intent(ctx, MusicService::class.java)
startForegroundService(intent)
val n = mNotificationBuilder.build()
// do sth
startForeground(Define.NOTIFICATION_ID, n)
} catch (e: Exception) {
Log.e(TAG, "startForegroundNotification: " + e.message)
}
}
It's my onCreate()
override fun onCreate() {
super.onCreate()
createNotificationChannel()
prepareAndStartForeground()
}
My onStartCommand()
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null) {
return START_STICKY_COMPATIBILITY
} else {
//....
//...
}
return START_STICKY
}
onRebind
, onBind
, onUnbind
methods like these
internal var binder: IBinder? = null
override fun onRebind(intent: Intent) {
stopForeground(true) // <- remove notification
}
override fun onBind(intent: Intent): IBinder? {
stopForeground(true) // <- remove notification
return binder
}
override fun onUnbind(intent: Intent): Boolean {
prepareAndStartForeground() // <- show notification again
return true
}
We need to clear something when onDestroy() calling
override fun onDestroy() {
super.onDestroy()
releaseService()
}
private fun releaseService() {
stopMedia()
stopTimer()
// sth like these
player = null
mContext = null
afChangeListener = null
mAudioBecomingNoisy = null
handler = null
mNotificationBuilder = null
mNotificationManager = null
mInstance = null
}
I hope this solution works properly for you.