Dalam situasi tertentu, Anda mungkin perlu menyediakan strategi threading kustom. Misalnya, Anda mungkin perlu menangani operasi asinkron berbasis callback. Dalam hal ini, Anda tidak dapat hanya mengandalkan Worker
karena tidak dapat melakukan pekerjaan secara tertutup. WorkManager mendukung kasus penggunaan ini dengan ListenableWorker
. ListenableWorker
adalah API pekerja tingkat paling dasar; Worker
, CoroutineWorker
, dan RxWorker
semuanya berasal dari class ini. ListenableWorker
hanya memberikan sinyal ketika pekerjaan akan dimulai dan dihentikan, sehingga menyerahkan threading sepenuhnya kepada Anda. Sinyal mulai pekerjaan dipanggil di thread utama, jadi sebaiknya Anda membuka thread latar belakang pilihan Anda secara manual.
Metode abstrak ListenableWorker.startWork()
menampilkan ListenableFuture
dari Result
. ListenableFuture
adalah antarmuka yang ringan: Future
adalah yang menyediakan fungsi untuk melampirkan pemroses dan menyebarkan pengecualian. Dalam metode startWork
, Anda diharapkan untuk menampilkan ListenableFuture
, yang akan Anda tetapkan dengan Result
operasi begitu selesai. Anda dapat membuat instance ListenableFuture
melalui salah satu dari dua cara berikut:
- Jika Anda menggunakan Guava, gunakan
ListeningExecutorService
. - Jika tidak, sertakan
councurrent-futures
dalam file gradle Anda dan gunakanCallbackToFutureAdapter
.
Jika ingin menjalankan beberapa tugas berdasarkan callback asinkron, Anda akan melakukan hal berikut:
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; }); } }
Apa yang terjadi jika pekerjaan Anda dihentikan? ListenableFuture
ListenableWorker
selalu dibatalkan saat pekerjaan diharapkan untuk berhenti. Dengan menggunakan CallbackToFutureAdapter
, Anda hanya perlu menambahkan pemroses pembatalan seperti berikut:
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; }); } }
Menjalankan ListenableWorker dalam proses yang berbeda
Anda juga dapat mengikat pekerja ke proses tertentu menggunakan
RemoteListenableWorker
,
implementasi ListenableWorker
.
RemoteListenableWorker
terikat ke proses tertentu dengan dua argumen tambahan
yang Anda berikan sebagai bagian dari data input saat membuat permintaan pekerjaan:
ARGUMENT_CLASS_NAME
dan ARGUMENT_PACKAGE_NAME
.
Contoh berikut menunjukkan pembuatan permintaan pekerjaan yang terikat dengan proses tertentu:
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();
Untuk setiap RemoteWorkerService
, Anda juga perlu menambahkan definisi layanan di
file 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>