So, with Android O, you need to have your service running as a foreground service if you want to receive more than just a few location updates per hour.
I noticed that the old method for starting a foreground service does seem to work on O. i.e.
startForeground(NOTIFICATION_ID, getNotification());
According to the behaviour changes guide here: https://developer.android.com/preview/behavior-changes.html
The NotificationManager.startServiceInForeground() method starts a foreground service. The old way to start a foreground service no longer works.
Though the new method only works when targeting O, it seems that the old method still seems to work on an O device whether targeting O or not.
Edit Including example:
The Google sample project LocationUpdatesForegroundService actually has a working example where you can see the issue first hand. https://github.com/googlesamples/android-play-location/tree/master/LocationUpdatesForegroundService
The startForeground method seems to work without issue whether targeting and compiling against API level 25 OR targeting and compiling against O (as directed to here: https://developer.android.com/preview/migration.html#uya)
So, to reproduce:
Service is running in foreground (shown by icon in notification shade). Location updates are coming through as expected (every 10 seconds) even on a device running O. What I am missing here?
To remove the service from the foreground, call stopForeground() . This method takes a boolean, which indicates whether to remove the status bar notification as well. Note that the service continues to run. If you stop the service while it's running in the foreground, its notification is removed.
A foreground service performs some operation that is noticeable to the user. For example, an audio app would use a foreground service to play an audio track. Foreground services must display a Notification. Foreground services continue running even when the user isn't interacting with the app.
The new context. startForegroundService() method starts a foreground service but with a implicit contract that service will call start foreground within 5 second of its creation. You can also call startService and startForegroundService for different OS version.
This worked for me.
- In Activity class, start service using startForegroundService() instead of startService()
Intent myService = new Intent(this, MyService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(myService); } else { startService(myService); }
- Now in Service class in onStartCommand() do as following
@Override public int onStartCommand(Intent intent, int flags, int startId) { ...... if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Notification.Builder builder = new Notification.Builder(this, ANDROID_CHANNEL_ID) .setContentTitle(getString(R.string.app_name)) .setContentText(text) .setAutoCancel(true); Notification notification = builder.build(); startForeground(1, notification); } else { NotificationCompat.Builder builder = new NotificationCompat.Builder(this) .setContentTitle(getString(R.string.app_name)) .setContentText(text) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setAutoCancel(true); Notification notification = builder.build(); startForeground(1, notification); } return START_NOT_STICKY; }
Note: Using Notification.Builder instead of NotificationCompat.Builder made it work. Only in Notification.Builder you will need to provide Channel ID which is new feature in Android Oreo.
Hope it works!
If you target API level 28 or higher, you need FOREGROUND_SERVICE permission otherwise, your app will crash.
Just add this to the AndroidManifest.xml file.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
In the Activity (or any context that starts the foreground service), call this:
Intent intent = new Intent(this, MyService.class) ContextCompat.startForegroundService(context, intent);
When the service has started, create a notification channel using similar code to what Android docs say, and then create a builder and use it:
final Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID).setSmallIcon(...)// .setPriority(...).setCategory(...).setContentTitle(...).setContentText(...).setTicker(...); // and maybe other preparations to the notification... startForeground(notificationId, builder.build());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With