In bestimmten Situationen müssen Sie möglicherweise eine benutzerdefinierte Threading-Strategie festlegen. Beispielsweise kann es sein, dass Sie einen Callback-basierten asynchronen Vorgang verarbeiten müssen.
WorkManager unterstützt diesen Anwendungsfall mit ListenableWorker
.
ListenableWorker
ist die einfachste Worker-API. Worker
, CoroutineWorker
und RxWorker
leiten alle aus dieser Klasse ab. Ein ListenableWorker
signalisiert nur, wann die Arbeit beginnen und beendet werden soll, und überlässt das Threading ganz dir. Das Startsignal wird im Hauptthread aufgerufen. Daher ist es sehr wichtig, dass Sie manuell einen Hintergrundthread Ihrer Wahl aufrufen.
Die abstrakte Methode ListenableWorker.startWork()
gibt einen ListenableFuture
von Result
zurück. Eine ListenableFuture
ist eine einfache Schnittstelle: Sie ist eine Future
, die Funktionen zum Anhängen von Listenern und zur Weitergabe von Ausnahmen bietet. In der Methode startWork
wird ein ListenableFuture
zurückgegeben, das Sie nach Abschluss des Vorgangs mit dem Result
des Vorgangs festlegen. Sie können ListenableFuture
-Instanzen auf zwei Arten erstellen:
- Wenn du Guava verwendest, verwende
ListeningExecutorService
. - Fügen Sie andernfalls
councurrent-futures
in die Gradle-Datei ein und verwenden SieCallbackToFutureAdapter
.
Wenn Sie Vorgänge basierend auf einem asynchronen Callback ausführen möchten, gehen Sie so vor:
Kotlin
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 } } }
Java
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; }); } }
Was passiert, wenn Ihre Arbeit angehalten wird?
ListenableFuture
von ListenableWorker
wird immer abgebrochen, wenn die Arbeit voraussichtlich beendet wird. Mit einem CallbackToFutureAdapter
müssen Sie lediglich einen Abbruch-Listener hinzufügen:
Kotlin
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 } } }
Java
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 in einem anderen Prozess ausführen
Sie können einen Worker auch mit RemoteListenableWorker
, einer Implementierung von ListenableWorker
, an einen bestimmten Prozess binden.
RemoteListenableWorker
bindet sich mit zwei zusätzlichen Argumenten an einen bestimmten Prozess, die Sie beim Erstellen der Arbeitsanfrage als Teil der Eingabedaten angeben: ARGUMENT_CLASS_NAME
und ARGUMENT_PACKAGE_NAME
.
Das folgende Beispiel zeigt, wie eine Arbeitsanfrage erstellt wird, die an einen bestimmten Prozess gebunden ist:
Kotlin
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()
Java
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();
Für jede RemoteWorkerService
müssen Sie außerdem eine Dienstdefinition in die AndroidManifest.xml
-Datei einfügen:
<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>