ListenableWorker でのスレッド化

状況によっては、カスタムのスレッド戦略が必要になることもあります。対象 コールバックベースの非同期オペレーションの処理が必要になることがあります。 WorkManager は、 ListenableWorkerListenableWorker は最も基本的なワーカー API です。 Worker, CoroutineWorkerRxWorker はすべてこのクラスの派生クラスです。 ListenableWorker は、処理の開始、停止、終了のタイミングのみを通知します。 スレッド化はすべて任意です。処理開始シグナルはメイン スレッドで そのため、メインスレッドのバックグラウンド スレッドに 手動で選択する必要はありません。

抽象メソッド ListenableWorker.startWork() 次のリクエストの ListenableFuture を返します。 ResultListenableFuture は軽量なインターフェースで、次の機能を提供する Future です。 リスナーをアタッチして例外を伝播する機能があります。 startWork メソッドでは、ListenableFuture を返すことが想定されています。 オペレーションが完了すると、オペレーションの Result に設定されます。新しい 次の 2 つの方法のいずれかで ListenableFuture インスタンスを使用できます。

  1. Guava を使用する場合、ListeningExecutorService を使用する。
  2. それ以外の場合は、 councurrent-futures 使用して、 CallbackToFutureAdapter

非同期コールバックに基づいて処理を実行する場合は、 次のような操作を行います。

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;
        });
    }
}

業務内容が 停止されているか? 処理が完了すると、ListenableWorkerListenableFuture は常にキャンセルされます。 停止すると予想されますCallbackToFutureAdapter を使用するだけで、 次のように設定します。

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 を実行する

ListenableWorker の実装である RemoteListenableWorker を使用して、ワーカーを特定のプロセスにバインドすることもできます。

RemoteListenableWorker は、2 つの引数 ARGUMENT_CLASS_NAMEARGUMENT_PACKAGE_NAME を追加で使用して、特定のプロセスにバインドします。これらの引数は、処理リクエストの作成時に入力データの一部として指定します。

次の例は、特定のプロセスにバインドされた処理リクエストの作成を示しています。

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();

また、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>

サンプル