Потоки в ListenableWorker
Оптимизируйте свои подборки
Сохраняйте и классифицируйте контент в соответствии со своими настройками.
В определенных ситуациях вам может потребоваться предоставить собственную стратегию потоковой обработки. Например, вам может потребоваться обработать асинхронную операцию на основе обратного вызова. WorkManager поддерживает этот вариант использования с помощью ListenableWorker
. ListenableWorker
— это самый простой рабочий API; Worker
, CoroutineWorker
и RxWorker
являются производными от этого класса. ListenableWorker
сигнализирует только о том, когда работа должна начинаться и останавливаться, и оставляет управление потоками полностью на ваше усмотрение. Сигнал начала работы вызывается в основном потоке, поэтому очень важно вручную перейти к фоновому потоку по вашему выбору.
Абстрактный метод ListenableWorker.startWork()
возвращает ListenableFuture
Result
. ListenableFuture
— это облегченный интерфейс: это Future
, предоставляющий функциональные возможности для подключения прослушивателей и распространения исключений. Ожидается, что в методе startWork
вы вернете ListenableFuture
, который вы установите вместе с Result
операции после ее завершения. Экземпляры ListenableFuture
можно создавать одним из двух способов:
- Если вы используете Guava, используйте
ListeningExecutorService
. - В противном случае включите
councurrent-futures
в свой файл градиента и используйте CallbackToFutureAdapter
.
Если вы хотите выполнить какую-то работу на основе асинхронного обратного вызова, вы должны сделать что-то вроде этого:
Котлин
class CallbackWorker(
context: Context,
params: WorkerParameters
) : ListenableWorker(context, params) {
override fun startWork(): ListenableFuture<Result> {
return CallbackToFutureAdapter.getFuture { completer ->
val callback = object : Callback {
var successes = 0
override fun onFailure(call: Call, e: IOException) {
completer.setException(e)
}
override fun onResponse(call: Call, response: Response) {
successes++
if (successes == 100) {
completer.set(Result.success())
}
}
}
repeat(100) {
downloadAsynchronously("https://example.com", callback)
}
callback
}
}
}
Ява
public class CallbackWorker extends ListenableWorker {
public CallbackWorker(Context context, WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public ListenableFuture<Result> startWork() {
return CallbackToFutureAdapter.getFuture(completer -> {
Callback callback = new Callback() {
int successes = 0;
@Override
public void onFailure(Call call, IOException e) {
completer.setException(e);
}
@Override
public void onResponse(Call call, Response response) {
successes++;
if (successes == 100) {
completer.set(Result.success());
}
}
};
for (int i = 0; i < 100; i++) {
downloadAsynchronously("https://www.example.com", callback);
}
return callback;
});
}
}
Что произойдет, если вашу работу остановят ? ListenableFuture
объекта ListenableWorker
всегда отменяется, когда ожидается остановка работы. Используя CallbackToFutureAdapter
, вам просто нужно добавить прослушиватель отмены, как показано ниже:
Котлин
class CallbackWorker(
context: Context,
params: WorkerParameters
) : ListenableWorker(context, params) {
override fun startWork(): ListenableFuture<Result> {
return CallbackToFutureAdapter.getFuture { completer ->
val callback = object : Callback {
var successes = 0
override fun onFailure(call: Call, e: IOException) {
completer.setException(e)
}
override fun onResponse(call: Call, response: Response) {
++successes
if (successes == 100) {
completer.set(Result.success())
}
}
}
completer.addCancellationListener(cancelDownloadsRunnable, executor)
repeat(100) {
downloadAsynchronously("https://example.com", callback)
}
callback
}
}
}
Ява
public class CallbackWorker extends ListenableWorker {
public CallbackWorker(Context context, WorkerParameters params) {
super(context, params);
}
@NonNull
@Override
public ListenableFuture<Result> startWork() {
return CallbackToFutureAdapter.getFuture(completer -> {
Callback callback = new Callback() {
int successes = 0;
@Override
public void onFailure(Call call, IOException e) {
completer.setException(e);
}
@Override
public void onResponse(Call call, Response response) {
++successes;
if (successes == 100) {
completer.set(Result.success());
}
}
};
completer.addCancellationListener(cancelDownloadsRunnable, executor);
for (int i = 0; i < 100; ++i) {
downloadAsynchronously("https://www.example.com", callback);
}
return callback;
});
}
}
Запуск ListenableWorker в другом процессе
Вы также можете привязать работника к определенному процессу с помощью RemoteListenableWorker
, реализации ListenableWorker
.
RemoteListenableWorker
привязывается к конкретному процессу с помощью двух дополнительных аргументов, которые вы предоставляете как часть входных данных при создании рабочего запроса: ARGUMENT_CLASS_NAME
и ARGUMENT_PACKAGE_NAME
.
В следующем примере показано создание рабочего запроса, привязанного к определенному процессу:
Котлин
val PACKAGE_NAME = "com.example.background.multiprocess"
val serviceName = RemoteWorkerService::class.java.name
val componentName = ComponentName(PACKAGE_NAME, serviceName)
val data: Data = Data.Builder()
.putString(ARGUMENT_PACKAGE_NAME, componentName.packageName)
.putString(ARGUMENT_CLASS_NAME, componentName.className)
.build()
return OneTimeWorkRequest.Builder(ExampleRemoteListenableWorker::class.java)
.setInputData(data)
.build()
Ява
String PACKAGE_NAME = "com.example.background.multiprocess";
String serviceName = RemoteWorkerService.class.getName();
ComponentName componentName = new ComponentName(PACKAGE_NAME, serviceName);
Data data = new Data.Builder()
.putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName())
.putString(ARGUMENT_CLASS_NAME, componentName.getClassName())
.build();
return new OneTimeWorkRequest.Builder(ExampleRemoteListenableWorker.class)
.setInputData(data)
.build();
Для каждого RemoteWorkerService
вам также необходимо добавить определение службы в файл AndroidManifest.xml
:
<manifest ... >
<service
android:name="androidx.work.multiprocess.RemoteWorkerService"
android:exported="false"
android:process=":worker1" />
<service
android:name=".RemoteWorkerService2"
android:exported="false"
android:process=":worker2" />
...
</manifest>
Образцы
Контент и образцы кода на этой странице предоставлены по лицензиям. Java и OpenJDK – это зарегистрированные товарные знаки корпорации Oracle и ее аффилированных лиц.
Последнее обновление: 2025-07-29 UTC.
[[["Прост для понимания","easyToUnderstand","thumb-up"],["Помог мне решить мою проблему","solvedMyProblem","thumb-up"],["Другое","otherUp","thumb-up"]],[["Отсутствует нужная мне информация","missingTheInformationINeed","thumb-down"],["Слишком сложен/слишком много шагов","tooComplicatedTooManySteps","thumb-down"],["Устарел","outOfDate","thumb-down"],["Проблема с переводом текста","translationIssue","thumb-down"],["Проблемы образцов/кода","samplesCodeIssue","thumb-down"],["Другое","otherDown","thumb-down"]],["Последнее обновление: 2025-07-29 UTC."],[],[],null,["# Threading in ListenableWorker\n\nIn certain situations, you may need to provide a custom threading strategy. For\nexample, you may need to handle a callback-based asynchronous operation.\nWorkManager supports this use case with\n[`ListenableWorker`](/reference/androidx/work/ListenableWorker).\n`ListenableWorker` is the most basic worker API;\n[`Worker`](/reference/androidx/work/Worker),\n[`CoroutineWorker`](/reference/kotlin/androidx/work/CoroutineWorker), and\n[`RxWorker`](/reference/androidx/work/RxWorker) all derive from this class. A\n`ListenableWorker` only signals when the work should start and stop and leaves\nthe threading entirely up to you. The start work signal is invoked on the main\nthread, so it is very important that you go to a background thread of your\nchoice manually.\n\nThe abstract method\n[`ListenableWorker.startWork()`](/reference/androidx/work/ListenableWorker#startWork())\nreturns a `ListenableFuture` of the\n[`Result`](/reference/androidx/work/ListenableWorker.Result). A\n`ListenableFuture` is a lightweight interface: it is a `Future` that provides\nfunctionality for attaching listeners and propagating exceptions. In the\n`startWork` method, you are expected to return a `ListenableFuture`, which you\nwill set with the `Result` of the operation once it's completed. You can create\n`ListenableFuture` instances in one of two ways:\n\n1. If you use Guava, use `ListeningExecutorService`.\n2. Otherwise, include [`councurrent-futures`](/jetpack/androidx/releases/concurrent#declaring_dependencies) in your gradle file and use [`CallbackToFutureAdapter`](/reference/androidx/concurrent/futures/CallbackToFutureAdapter).\n\nIf you wanted to execute some work based on an asynchronous callback, you would\ndo something like this: \n\n### Kotlin\n\n```kotlin\nclass CallbackWorker(\n context: Context,\n params: WorkerParameters\n) : ListenableWorker(context, params) {\n override fun startWork(): ListenableFuture\u003cResult\u003e {\n return CallbackToFutureAdapter.getFuture { completer -\u003e\n val callback = object : Callback {\n var successes = 0\n\n override fun onFailure(call: Call, e: IOException) {\n completer.setException(e)\n }\n\n override fun onResponse(call: Call, response: Response) {\n successes++\n if (successes == 100) {\n completer.set(Result.success())\n }\n }\n }\n\n repeat(100) {\n downloadAsynchronously(\"https://example.com\", callback)\n }\n\n callback\n }\n }\n}\n```\n\n### Java\n\n```java\npublic class CallbackWorker extends ListenableWorker {\n\n public CallbackWorker(Context context, WorkerParameters params) {\n super(context, params);\n }\n\n @NonNull\n @Override\n public ListenableFuture\u003cResult\u003e startWork() {\n return CallbackToFutureAdapter.getFuture(completer -\u003e {\n Callback callback = new Callback() {\n int successes = 0;\n\n @Override\n public void onFailure(Call call, IOException e) {\n completer.setException(e);\n }\n\n @Override\n public void onResponse(Call call, Response response) {\n successes++;\n if (successes == 100) {\n completer.set(Result.success());\n }\n }\n };\n\n for (int i = 0; i \u003c 100; i++) {\n downloadAsynchronously(\"https://www.example.com\", callback);\n }\n return callback;\n });\n }\n}\n```\n\nWhat happens if your work is\n[stopped](/topic/libraries/architecture/workmanager/how-to/managing-work#cancelling)?\nA `ListenableWorker`'s `ListenableFuture` is always cancelled when the work is\nexpected to stop. Using a `CallbackToFutureAdapter`, you simply have to add a\ncancellation listener, as follows: \n\n### Kotlin\n\n```kotlin\nclass CallbackWorker(\n context: Context,\n params: WorkerParameters\n) : ListenableWorker(context, params) {\n override fun startWork(): ListenableFuture\u003cResult\u003e {\n return CallbackToFutureAdapter.getFuture { completer -\u003e\n val callback = object : Callback {\n var successes = 0\n\n override fun onFailure(call: Call, e: IOException) {\n completer.setException(e)\n }\n\n override fun onResponse(call: Call, response: Response) {\n ++successes\n if (successes == 100) {\n completer.set(Result.success())\n }\n }\n }\n\n completer.addCancellationListener(cancelDownloadsRunnable, executor)\n\n repeat(100) {\n downloadAsynchronously(\"https://example.com\", callback)\n }\n\n callback\n }\n }\n}\n```\n\n### Java\n\n```java\npublic class CallbackWorker extends ListenableWorker {\n\n public CallbackWorker(Context context, WorkerParameters params) {\n super(context, params);\n }\n\n @NonNull\n @Override\n public ListenableFuture\u003cResult\u003e startWork() {\n return CallbackToFutureAdapter.getFuture(completer -\u003e {\n Callback callback = new Callback() {\n int successes = 0;\n\n @Override\n public void onFailure(Call call, IOException e) {\n completer.setException(e);\n }\n\n @Override\n public void onResponse(Call call, Response response) {\n ++successes;\n if (successes == 100) {\n completer.set(Result.success());\n }\n }\n };\n\n completer.addCancellationListener(cancelDownloadsRunnable, executor);\n\n for (int i = 0; i \u003c 100; ++i) {\n downloadAsynchronously(\"https://www.example.com\", callback);\n }\n return callback;\n });\n }\n}\n```\n\nRunning a ListenableWorker in a different process\n-------------------------------------------------\n\nYou can also bind a worker to a specific process by using\n[`RemoteListenableWorker`](/reference/kotlin/androidx/work/multiprocess/RemoteListenableWorker),\nan implementation of `ListenableWorker`.\n\n`RemoteListenableWorker` binds to a specific process with two extra arguments\nthat you provide as part of the input data when building the work request:\n`ARGUMENT_CLASS_NAME` and `ARGUMENT_PACKAGE_NAME`.\n\nThe following example demonstrates building a work request that is bound to a\nspecific process: \n\n### Kotlin\n\n```kotlin\nval PACKAGE_NAME = \"com.example.background.multiprocess\"\n\nval serviceName = RemoteWorkerService::class.java.name\nval componentName = ComponentName(PACKAGE_NAME, serviceName)\n\nval data: Data = Data.Builder()\n .putString(ARGUMENT_PACKAGE_NAME, componentName.packageName)\n .putString(ARGUMENT_CLASS_NAME, componentName.className)\n .build()\n\nreturn OneTimeWorkRequest.Builder(ExampleRemoteListenableWorker::class.java)\n .setInputData(data)\n .build()\n```\n\n### Java\n\n```java\nString PACKAGE_NAME = \"com.example.background.multiprocess\";\n\nString serviceName = RemoteWorkerService.class.getName();\nComponentName componentName = new ComponentName(PACKAGE_NAME, serviceName);\n\nData data = new Data.Builder()\n .putString(ARGUMENT_PACKAGE_NAME, componentName.getPackageName())\n .putString(ARGUMENT_CLASS_NAME, componentName.getClassName())\n .build();\n\nreturn new OneTimeWorkRequest.Builder(ExampleRemoteListenableWorker.class)\n .setInputData(data)\n .build();\n```\n\nFor each `RemoteWorkerService`, you also need to add a service definition in\nyour `AndroidManifest.xml` file: \n\n```xml\n\u003cmanifest ... \u003e\n \u003cservice\n android:name=\"androidx.work.multiprocess.RemoteWorkerService\"\n android:exported=\"false\"\n android:process=\":worker1\" /\u003e\n\n \u003cservice\n android:name=\".RemoteWorkerService2\"\n android:exported=\"false\"\n android:process=\":worker2\" /\u003e\n ...\n\u003c/manifest\u003e\n```\n\nSamples\n-------\n\n- [WorkManagerMultiProcessSample](https://github.com/android/architecture-components-samples/tree/main/WorkManagerMultiprocessSample)"]]