When you need to perform long-running tasks and the application is in the background, you will encounter Background execution restrictions , this feature was added after Android 8.0. We encourage developers to make behavior changes to improve the user experience of the whole platform.
In order to make it easier to adapt to different use scenarios, we added functions to WorkManager to improve the experience of developers in complying with background task restrictions.
We recommend using WorkManager to handle long-running tasks that need to be executed immediately.
Read this article to learn about the benefits of long-running and immediate tasks handled through WorkManager and how to configure them.
API introduction
since WorkManager version 2.3.0 As a result, each Worker can invoke the method in the foreground service. ListenableWorker As the base class of Worker, it provides a new setForegroundAsync() Function.
In this paper CoroutineWorker For example. In CoroutineWorker, setForegroundAsync() is encapsulated in a pending setForeground() Function. This class also provides a suspended doWork function, which supports code running away from the main thread. However, the whole content of this article also applies to the related functions of other Worker classes.
When setforegroup (async) is called, once the constraints are met, the scheduled task will be executed immediately in the foreground service. In addition, WorkManager is responsible for handling the service lifecycle. The task running in the Worker of the foreground service will not be limited by the background task for ten minutes.
Start with immediate execution
Let's take a look at how to make an existing worker perform tasks in the foreground service.
Let's start with a very simple doWork() function. The code is executed asynchronously. Whether it succeeds or fails, there will be a corresponding Result return.
/* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ override suspend fun doWork(): Result { try { //Code to execute return Result.success() } catch (throwable: Throwable) { //Clean and output return Result.failure() } }
In doWork(), you also need to tell the work manager that the task should be executed immediately in the foreground service.
To do this, you need to create a ForegroundInfo Object as a parameter to setforegroup(). Foreroundinfo requires two parameters, one is Notification ID, and the other is to be displayed Notification.
When the constraints are met, the following information can be used to create and run the foreground service.
Create foreroundinfo
To create foreroundinfo correctly, you only need the following three steps:
- Create a Notification
- Create a Notification Channel
- Bring notifications into foreroundinfo
In the following code, createforeroundinfo() calls createforeroundinfo(), and the createNotification() function populates the notification and creates the corresponding channel.
/* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ /** *Create foreroundinfo for the Worker running the foreground service */ private fun createForegroundInfo(): ForegroundInfo { //Each Notification needs to use a different id val notificationId = 1 return ForegroundInfo(notificationId, createNotification()) } /** * Create Notification and required channel for foreground service running task (above Android o version) */ private fun createNotification(): Notification { //PendingIntent can be used to cancel the Worker val intent = WorkManager.getInstance(context).createCancelPendingIntent(id) val builder = Builder(context, channelId) .setContentTitle(title) .setTicker(title) .setSmallIcon(R.drawable.baseline_gradient) .setOngoing(true) .addAction(drawable.ic_delete, cancel, intent) if (VERSION.SDK_INT >= VERSION_CODES.O) { createNotificationChannel(channelId, name).also { builder.setChannelId(it.id) } } return builder.build() } /** * Create the required notification channel for Android O and above devices */ @TargetApi(VERSION_CODES.O) private fun createNotificationChannel( channelId: String, name: String ): NotificationChannel { return NotificationChannel( channelId, name, NotificationManager.IMPORTANCE_LOW ).also { channel -> notificationManager.createNotificationChannel(channel) } }
Perform tasks in the front office
Now put these together. We have implemented the doWork function. We can call setforegroup() and pass the required information by calling createforeroundinfo().
/* Copyright 2020 Google LLC. SPDX-License-Identifier: Apache-2.0 */ override suspend fun doWork(): Result { try { setForeground(createForegroundInfo()) //Code to execute return Result.success(workDataOf(KEY_RESULT to result)) } catch (throwable: Throwable) { //Clean up and output logs return Result.failure() } }
⚠️⚠️⚠️
Before the long-running task starts, call setforegroup().
Otherwise, before setforegroup() is called, your Worker will be regarded as a non foreground service, which may lead to the cancellation of this task or other undesirable results.
⚠️⚠️⚠️
next step
Now that you know when and how to use long-running worker s, you can go to the next step and start implementing them in your application. For more information, see the following resources:
View WorkManager in GitHub Sample code.
Please refer to the code for executing tasks in the foreground service:
For a detailed guide to running worker and front office services for a long time, as well as more information on topics, please refer to:
- WorkManager's advanced guide | supports long-running workers
- Background processing Guide
- Kotlin collaboration on Android
The WorkManager series helps you understand the features of WorkManager from basic to advanced:
- Android Jetpack WorkManager | Android Chinese teaching video
- Practice of WorkManager in Kotlin
- WorkManager: recurring tasks
- Custom WorkManager - Basic Concepts
- Customizing WorkManager with Dagger
Google IssueTracker Submit any problems encountered, which will help us optimize features and fix vulnerabilities at the first time.