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?
After too much struggle with this crash finally, I fixed this exception completely and find the solution.
Make sure that have done this stuff in your service I list them as below : (some of this stuff are repetitious as mentioned in another answer I just write them again).
1- Call
startForeground()
in both onCreate and onStartCommand.(it's ok to call startForeground() many times)
@Override
public void onCreate() {
super.onCreate();
startCommand();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent == null) {
return START_NOT_STICKY;
}
final int command = intent.getIntExtra(MAIN_SERVICE_COMMAND_KEY, -1);
if (command == MAIN_SERVICE_START_COMMAND) {
startCommand();
return START_STICKY;
}
return START_NOT_STICKY;
}
private void startCommand() {
createNotificationAndStartForeground();
runningStatus.set(STARTED);
}
2- Stop your service using
context.stopService()
, there is no need to call stopForeground() or stopSelf().
try {
context.stopService(
new Intent(
context,
NavigationService.class
)
);
} catch (Exception ex) {
Crashlytics.logException(ex);
LogManager.e("Service manager can't stop service ", ex);
}
3- Start your service using
ContextCompat.startForegroundService()
it will handle different API versions.
ContextCompat.startForegroundService(
context,
NavigationService.getStartIntent(context)
);
4- If your service has actions ( need pending Intents ) handle your pending intents with a Broadcast receiver rather than your current service( it will call your service on Create() and can be dangerous, or use PendingIntent.FLAG_NO_CREATE) , it's a good practice to have a specific Broadcast receiver for handling your service notification actions, I mean create all your pending intents using PendingIntent.getBroadcast().
private PendingIntent getStopActionPendingIntent() {
final Intent stopNotificationIntent = getBroadCastIntent();
stopNotificationIntent.setAction(BROADCAST_STOP_SERVICE);
return getPendingIntent(stopNotificationIntent);
}
private PendingIntent getPendingIntent(final Intent intent) {
return PendingIntent.getBroadcast(
this,
0,
intent,
0
);
}
new NotificationCompat.Builder(this, CHANNEL_ID)
.addAction(
new NotificationCompat.Action(
R.drawable.notification,
getString(R.string.switch_off),
getStopActionPendingIntent()
)
)
5- Always before stop your service make sure that your service is created and started (I Create a global class that has my service state)
if (navigationServiceStatus == STARTED) {
serviceManager.stopNavigationService();
}
6- Set your notificationId to a long number such as 121412.
7- Using NotificationCompat.Builder will handle different API versions you just need to create notification channel for Build versions >= Build.VERSION_CODES.O.(This one is not a solution just make your code more readable)
8- Add
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
permission to your manifest. (this one is mentioned in android docs) Android Foreground Service
hope it helps :))