Workers: They Do Work
The work that you want to have done in the background needs to be wrapped in a Worker
subclass. This is an abstract
class with one abstract
method: doWork()
. In that method, you put your work to be done in the background.
Note that:
-
doWork()
will keep the device awake, so you do not have to worry about the CPU powering down while your work is ongoing -
doWork()
is called on a background thread, so you do not need to fork one yourself -
doWork()
needs to return aListenableWorker.Result
object indicating if the work succeeded or failed, sodoWork()
should not be starting other background threads (directly or through libraries) -
doWork()
cannot run forever — at best, it might run for 10 minutes before it is terminated, and it is possible that it will have less time than that
As noted above, doWork()
returns a ListenableWorker.Result
object. There are static factory methods on ListenableWorker.Result
that you use to create instances. Those factory methods represent three main result scenarios:
-
success()
, which is what you are hoping for -
retry()
, which indicates that for one reason or another you could not do the work but would likeWorkManager
to retry the work in a little while -
failure()
, which indicates that the work could not be done and a later retry is likely to fail as well, so you are giving up
Beyond the return value and the aforementioned limitations on what you can do in doWork()
, the actual business logic is up to you.
The DownloadWork
sample module in the Sampler
and SamplerJ
projects contains a DownloadWorker
class that downloads a file using OkHttp and a companion library named Okio:
package com.commonsware.jetpack.work.download;
import android.content.Context;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import androidx.annotation.NonNull;
import androidx.work.ListenableWorker;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okio.BufferedSink;
import okio.Okio;
public class DownloadWorker extends Worker {
public static final String KEY_URL="url";
public static final String KEY_FILENAME="filename";
public DownloadWorker(@NonNull Context context,
@NonNull WorkerParameters workerParams) {
super(context, workerParams);
}
@NonNull
@Override
public Result doWork() {
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder()
.url(getInputData().getString(KEY_URL))
.build();
try (Response response=client.newCall(request).execute()) {
File dir=getApplicationContext().getCacheDir();
File downloadedFile=
new File(dir, getInputData().getString(KEY_FILENAME));
BufferedSink sink=Okio.buffer(Okio.sink(downloadedFile));
sink.writeAll(response.body().source());
sink.close();
}
catch (IOException e) {
Log.e(getClass().getSimpleName(), "Exception downloading file", e);
return ListenableWorker.Result.failure();
}
return ListenableWorker.Result.success();
}
}
package com.commonsware.jetpack.work.download
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters
import okhttp3.OkHttpClient
import okhttp3.Request
import okio.buffer
import okio.sink
import java.io.File
import java.io.IOException
class DownloadWorker(context: Context, workerParams: WorkerParameters) :
Worker(context, workerParams) {
override fun doWork(): Result {
val client = OkHttpClient()
val request = Request.Builder()
.url(inputData.getString(KEY_URL)!!)
.build()
try {
client.newCall(request).execute().use { response ->
val dir = applicationContext.cacheDir
val downloadedFile = File(dir, inputData.getString(KEY_FILENAME)!!)
val sink = downloadedFile.sink().buffer()
response.body?.let { sink.writeAll(it.source()) }
sink.close()
}
} catch (e: IOException) {
Log.e(javaClass.simpleName, "Exception downloading file", e)
return Result.failure()
}
return Result.success()
}
companion object {
const val KEY_URL = "url"
const val KEY_FILENAME = "filename"
}
}
Worker
— from which DownloadWorker
inherits — has a two-parameter constructor, taking a Context
and a WorkerParameters
object. In many cases, you can just chain to the superclass constructor, as DownloadWorker
does.
Pretty much everything inside of doWork()
is just application code that does the download and returns success()
if the download succeeded or failure()
if there was some exception during the download.
This doWork()
method is using two methods that we get from Worker
:
-
getApplicationContext()
, which works like the similarly-named method onContext
, returning you theApplication
singleton, in case you need aContext
-
getInputData()
, which we will examine more closely later in the chapter
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.