در شرایط خاص، ممکن است نیاز داشته باشید که یک استراتژی threading سفارشی ارائه کنید. به عنوان مثال، ممکن است لازم باشد یک عملیات ناهمزمان مبتنی بر تماس را مدیریت کنید. WorkManager این مورد استفاده را با ListenableWorker
پشتیبانی می کند. ListenableWorker
اساسی ترین API کارگر است. Worker
، CoroutineWorker
و RxWorker
همگی از این کلاس مشتق شدهاند. ListenableWorker
فقط زمان شروع و توقف کار را علامت میدهد و کار را کاملاً به شما واگذار میکند. سیگنال شروع کار بر روی نخ اصلی فراخوانی می شود، بنابراین بسیار مهم است که به صورت دستی به یک رشته پس زمینه انتخابی خود بروید.
متد انتزاعی ListenableWorker.startWork()
یک ListenableFuture
از Result
برمیگرداند. ListenableFuture
یک رابط سبک وزن است: Future
است که عملکردی را برای اتصال شنوندگان و انتشار استثناها فراهم می کند. در روش startWork
، انتظار میرود که یک ListenableFuture
را برگردانید، که پس از تکمیل آن، آن را با Result
عملیات تنظیم میکنید. شما می توانید نمونه های ListenableFuture
را به یکی از دو روش ایجاد کنید:
- اگر از Guava استفاده می کنید، از
ListeningExecutorService
استفاده کنید. - در غیر این صورت،
councurrent-futures
در فایل gradle خود قرار دهید و از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; }); } }
اگر کار شما متوقف شود چه اتفاقی می افتد؟ یک ListenableWorker
's ListenableFuture
همیشه زمانی که انتظار می رود کار متوقف شود، لغو می شود. با استفاده از 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>