Threads in ListenableWorker

In bestimmten Situationen müssen Sie möglicherweise eine benutzerdefinierte Threading-Strategie bereitstellen. Für müssen Sie möglicherweise einen auf einem Rückruf basierenden asynchronen Vorgang abwickeln. WorkManager unterstützt diesen Anwendungsfall mit ListenableWorker ListenableWorker ist die einfachste Worker-API. Worker, CoroutineWorker und Die RxWorker-Elemente stammen alle aus dieser Klasse. A Mit ListenableWorker wird nur signalisiert, wann die Arbeit beginnen und anhalten soll und wann sie verlassen werden soll ganz Ihnen überlassen. Das Signal „Arbeit starten“ wird auf der Es ist also sehr wichtig, dass Sie sich im Hintergrund Ihres Threads eine manuelle Auswahl treffen.

Die abstrakte Methode ListenableWorker.startWork() gibt ListenableFuture des Werts Result A ListenableFuture ist eine schlanke Oberfläche: Es ist eine Future, die zum Anhängen von Listenern und Übertragen von Ausnahmen. Im startWork-Methode verwenden, wird erwartet, dass Sie eine ListenableFuture zurückgeben, wird nach Abschluss mit dem Result des Vorgangs festgelegt. Sie können ListenableFuture-Instanzen auf eine der beiden folgenden Arten:

  1. Wenn Sie Guava verwenden, verwenden Sie ListeningExecutorService.
  2. Andernfalls fügen Sie councurrent-futures in der Gradle-Datei ein und verwenden CallbackToFutureAdapter

Wenn Sie einige Arbeit basierend auf einem asynchronen Callback ausführen wollten, würden Sie Gehen Sie in etwa 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? Die ListenableFuture einer ListenableWorker wird immer abgebrochen, wenn die Arbeit voraussichtlich beendet wird. Mit einem CallbackToFutureAdapter müssen Sie einfach ein Kündigungs-Listener:

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, eine Implementierung von ListenableWorker.

RemoteListenableWorker bindet mit zwei zusätzlichen Argumenten an einen bestimmten Prozess. die Sie als Teil der Eingabedaten beim Erstellen der Arbeitsanfrage bereitstellen: ARGUMENT_CLASS_NAME und ARGUMENT_PACKAGE_NAME.

Im folgenden Beispiel sehen Sie, wie eine Arbeitsanfrage erstellt wird, die an eine bestimmten Prozess:

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 auch eine Dienstdefinition in Ihre AndroidManifest.xml-Datei:

<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>

Produktproben