That is only a quite simple app that covers some primary WorkManager utilization. It reveals you the way to schedule:
-
one-time work request
-
periodic work request
and
- submit a notification when the duty is completed.
For an entire information, seek advice from the official WorkManager information right here.
Add Work Supervisor Dependency
construct.gradle.kts instance
dependencies {
implementation ("androidx.work:work-runtime-ktx:2.7.1")
}
Inherit CoroutineWorker Class
To run a background process, it’s essential to create a employee class that inherits the CoroutineWorker
class. The overridden doWork()
technique is the place you carry out your background duties.
class DemoWorker(
non-public val appContext: Context,
params: WorkerParameters)
: CoroutineWorker(appContext, params) {
override droop enjoyable doWork(): End result {
delay(5000)
Log.d("DemoWorker", "do work finished!")
return End result.success()
}
}
By default, the coroutine runs on
Dispatchers.Default
. To modify to a unique coroutine dispatcher you should useCoroutineScope.withContext()
. For extra particulars, you’ll be able to go to my earlier weblog submit right here.
Instantiate WorkManager
WorkManager is a Singleton. You’ll be able to retrieve it by passing the applying context to the WorkManager.getInstance()
API.
WorkManager.getInstance(applicationContext)
You’ll be able to go in exercise context too, it will get transformed to software context anyway.
After you have the WorkManager, you’ll be able to set the work constraints and schedule the work request.
Set Work Constraints
You’ll be able to specify work constraints for the work request. The next is an instance of making NetworkType
constraints. NetworkType.CONNECTED
means the work runs on when your cellphone is linked to the web.
non-public val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.construct()
For different work constraints, seek advice from the official doc right here.
Schedule One-time Work Request
The next examples assume you could have the next variable setup.
non-public lateinit var workManager: WorkManager
non-public val constraints = Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.construct()
non-public val workName = "DemoWorker
This creates a one-time work request, with the NetworkType.CONNECTED
constraint. To schedule the work request, you’ll be able to name WorkManager.enqqueneUniqueWork().
val workRequest = OneTimeWorkRequestBuilder<DemoWorker>()
.setConstraints(constraints)
.construct()
workManager.enqueueUniqueWork(
workName,
ExistingWorkPolicy.REPLACE,
workRequest)
ExistingWorkPolicy.REPLACE
enum worth means if the identical work exists, it cancels the present one and replaces it.
In case your work requires greater precedence to run, you’ll be able to name the WorkRequest.Builder.setExpedited()
API. OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST
means if the app is run out of expedited quota, it falls again to non-expedited/common work requests.
val workRequest = OneTimeWorkRequestBuilder<DemoWorker>()
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.setConstraints(constraints)
.construct()
Schedule Periodic Work Request
val workRequest = PeriodicWorkRequestBuilder<DemoWorker>(
repeatInterval = 15,
TimeUnit.MINUTES
)
.construct()
workManager.enqueueUniquePeriodicWork(
workName,
ExistingPeriodicWorkPolicy.REPLACE,
workRequest)
You employ PeriodicWorkRequestBuilder<>()
to construct a periodic work request. Nevertheless, one crucial observe is the repeatInterval
should be equal to or better than quarter-hour. This does not appear to be documented anyplace.
For those who specify repeatInterval
lower than quarter-hour, it simply ignores your work request silently. Your app will not crash. There’s this warning in your log, however I wager you seemingly will not see it. Unhealthy resolution, it ought to simply crash the app for my part.
Interval period lesser than minimal allowed worth; Modified to 900000
If you name workManager.enqueueUniquePeriodicWork()
, your process runs instantly and runs once more at a specified repeatInterval
. Nevertheless, should you do not wish to run the duties instantly, you name the WorkRequest.Builder.setInitialDelay()
API.
val workRequest = PeriodicWorkRequestBuilder<DemoWorker>(
repeatInterval = 16,
TimeUnit.MINUTES
)
.setInitialDelay(5, TimeUnit.SECONDS)
.construct()
The above code runs the primary process after 5 seconds and repeats the duty each quarter-hour.
Cancel Work Request
You’ll be able to cancel the work request by passing in a novel work identify parameter to the WorkManager.cancelUniqueWork()
API.
workManager.cancelUniqueWork(workName)
Declare POST_NOTIFICATIONS Permission
Beginning on Android 13 (API degree 33 / Tiramisu), it’s essential to declare the notification permission and request it at run time.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:identify="android.permission.POST_NOTIFICATIONS" />
</manifest>
Request Runtime Permission
It is a easy runtime permission dialog composable perform that launches the permission request dialog in your app.
@Composable
enjoyable RuntimePermissionsDialog(
permission: String,
onPermissionGranted: () -> Unit,
onPermissionDenied: () -> Unit,
) {
if(Construct.VERSION.SDK_INT >= Construct.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(
LocalContext.present,
permission) != PackageManager.PERMISSION_GRANTED) {
val requestLocationPermissionLauncher =
rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
onPermissionGranted()
} else {
onPermissionDenied()
}
}
SideEffect {
requestLocationPermissionLauncher.launch(permission)
}
}
}
}
To name it, you’ll be able to simply go within the permission string and the callback tells you whether or not your permission is granted or denied.
@Composable
enjoyable MainScreen(viewModel: MainViewModel) {
RuntimePermissionsDialog(
Manifest.permission.POST_NOTIFICATIONS,
onPermissionDenied = {},
onPermissionGranted = {},
)
}
Create Notification Channel
Ranging from API 26 / Android Orea (Oeatmeal Cookie), a notification channel is required if you wish to submit a notification.
That is an instance of making a notification channel within the DemoWorker
coroutine employee class.
class DemoWorker(
non-public val appContext: Context,
params: WorkerParameters
) : CoroutineWorker(appContext, params) {
non-public val notificationChannelId = "DemoNotificationChannelId"
non-public enjoyable createNotificationChannel()
{
if (Construct.VERSION.SDK_INT >= Construct.VERSION_CODES.O) {
val notificationChannel = NotificationChannel(
notificationChannelId,
"DemoWorker",
NotificationManager.IMPORTANCE_DEFAULT,
)
val notificationManager: NotificationManager? =
getSystemService(
applicationContext,
NotificationManager::class.java)
notificationManager?.createNotificationChannel(
notificationChannel
)
}
}
}
Create the Notification
To create the notification, you name NotificationCompat.Builder()
by passing within the software context and the notificationChannelId
that’s used to create the notification channel within the earlier step.
class DemoWorker(
non-public val appContext: Context,
params: WorkerParameters
) : CoroutineWorker(appContext, params) {
non-public val notificationChannelId = "DemoNotificationChannelId"
non-public enjoyable createNotification() : Notification {
createNotificationChannel()
val mainActivityIntent = Intent(
applicationContext,
MainActivity::class.java)
var pendingIntentFlag by Delegates.notNull<Int>()
if (Construct.VERSION.SDK_INT >= Construct.VERSION_CODES.M) {
pendingIntentFlag = PendingIntent.FLAG_IMMUTABLE
} else {
pendingIntentFlag = PendingIntent.FLAG_UPDATE_CURRENT
}
val mainActivityPendingIntent = PendingIntent.getActivity(
applicationContext,
0,
mainActivityIntent,
pendingIntentFlag)
return NotificationCompat.Builder(
applicationContext,
notificationChannelId
)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle(applicationContext.getString(R.string.app_name))
.setContentText("Work Request Carried out!")
.setContentIntent(mainActivityPendingIntent)
.setAutoCancel(true)
.construct()
}
}
The mainActivityPendingIntent
is used to start out your app’s primary exercise when the notification is clicked.
Override getForegroundInfo()
For those who use notifications in your employee class, it’s essential to additionally override the getForegroundInfo()
droop perform. Your app crashes with out this override.
override droop enjoyable getForegroundInfo(): ForegroundInfo {
return ForegroundInfo(
0, createNotification()
)
}
Publish the Notification
To submit a notification, you utilize NotificationManagerCompat.Notify()
API.
class DemoWorker(
non-public val appContext: Context,
params: WorkerParameters
) : CoroutineWorker(appContext, params) {
non-public val notificationChannelId = "DemoNotificationChannelId"
override droop enjoyable doWork(): End result {
if (ActivityCompat.checkSelfPermission(
appContext,
Manifest.permission.POST_NOTIFICATIONS)
== PackageManager.PERMISSION_GRANTED
) {
with(NotificationManagerCompat.from(applicationContext)) {
notify(0, createNotification())
}
}
return End result.success()
}
}
Carried out
I additionally utilized a really comparable code to my easy RSS feed reader app to carry out background article sync each 24 hours.
That is finished by this SyncWorker class.
Supply Code
GitHub Repository: Demo_WorkManager