On application launch, app starts the service that should to do some network task. After targeting API level 26, my application fails to start service on Android 8.0 on back
Use startForegroundService()
instead of startService()
and don't forget to create startForeground(1,new Notification());
in your service within 5 seconds of starting service.
i had this problem too
added this library
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
and reinstalled the app solved this for me
To improve the user experience, Android 8.0 (API level 26) imposes limitations on what apps can do while running in the background.
Still if you need always running service, then you can use foreground service.
Background Service Limitations: While an app is idle, there are limits to its use of background services. This does not apply to foreground services, which are more noticeable to the user.
So you can make a foreground service. You will need to show a notification to user when your service is running. See this answer (There are many others)
A solution if -
You can make periodic task, 1. it starts your service, 2. service will do its work and 3. stops itself. By this your app will not be considered battery draining.
You can use periodic task with Alarm Manager, Job Scheduler, Evernote-Jobs or Work Manager.
I have tested forever running service with Work-Manager.
As @kosev said in his answer you can use JobIntentService. But I use an alternative solution - I catch IllegalStateException and start the service as foreground. For example, this function starts my service:
@JvmStatic
protected fun startService(intentAction: String, serviceType: Class<*>, intentExtraSetup: (Intent) -> Unit) {
val context = App.context
val intent = Intent(context, serviceType)
intent.action = intentAction
intentExtraSetup(intent)
intent.putExtra(NEED_FOREGROUND_KEY, false)
try {
context.startService(intent)
}
catch (ex: IllegalStateException) {
intent.putExtra(NEED_FOREGROUND_KEY, true)
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
}
else {
context.startService(intent)
}
}
}
and when I process Intent I do such thing:
override fun onHandleIntent(intent: Intent?) {
val needToMoveToForeground = intent?.getBooleanExtra(NEED_FOREGROUND_KEY, false) ?: false
if(needToMoveToForeground) {
val notification = notificationService.createSyncServiceNotification()
startForeground(notification.second, notification.first)
isInForeground = true
}
intent?.let {
getTask(it)?.process()
}
}
Yeah, that's because you can't start services in the background anymore on API 26. So you can start ForegroundService above API 26.
You'll have to use
ContextCompat.startForegroundService(...)
and post a notification while processing the leak.
The permitted situations are a temporary whitelist where the background service behaves the same as before Android O.
Under certain circumstances, a background app is placed on a temporary whitelist for several minutes. While an app is on the whitelist, it can launch services without limitation, and its background services are permitted to run. An app is placed on the whitelist when it handles a task that's visible to the user, such as:
- Handling a high-priority Firebase Cloud Messaging (FCM) message.
- Receiving a broadcast, such as an SMS/MMS message.
- Executing a PendingIntent from a notification.
- Starting a VpnService before the VPN app promotes itself to the foreground.
Source: https://developer.android.com/about/versions/oreo/background.html
So in other words if your background service does not meet the whitelist requirements you have to use the new JobScheduler. It's basically the same as a background service, but it gets called periodically instead of running in the background continuously.
If you're using an IntentService, you can change to a JobIntentService. See @kosev's answer below.