Trong một số trường hợp, có thể bạn sẽ cần đưa ra một chiến lược tạo luồng xử lý tuỳ chỉnh. Ví dụ, bạn có thể sẽ cần xử lý một thao tác không đồng bộ dựa trên lệnh gọi lại. Trong trường hợp này, bạn không thể chỉ dựa vào Worker
, vì lớp này không thể thực hiện công việc theo kiểu chặn. WorkManager hỗ trợ trường hợp sử dụng này bằng ListenableWorker
. ListenableWorker
là API worker cơ bản nhất; Worker
, CoroutineWorker
và RxWorker
đều xuất phát từ lớp này. ListenableWorker
chỉ báo hiệu khi nào công việc nên bắt đầu hay dừng lại, và để cho bạn quyết định toàn bộ việc tạo luồng xử lý. Vì tín hiệu bắt đầu công việc được gọi trên luồng chính (main thread), nên điều quan trọng là bạn phải chuyển đến luồng chạy nền (background thread) mà bạn chọn theo cách thủ công.
Phương thức trừu tượng ListenableWorker.startWork()
sẽ trả về một ListenableFuture
của Result
. ListenableFuture
là một giao diện có kích thước nhẹ, là một Future
cung cấp chức năng kết nối trình nghe và truyền bá các trường hợp ngoại lệ. Theo dự kiến, phương thức startWork
sẽ trả về một ListenableFuture
. Bạn sẽ đặt lớp này cùng với Result
của thao tác sau khi thao tác hoàn thành. Bạn có thể tạo các thực thể ListenableFuture
theo một trong hai cách sau:
- Nếu bạn dùng Guava, hãy sử dụng
ListeningExecutorService
. - Nếu không, hãy thêm
councurrent-futures
vào tệp gradle của bạn và sử dụngCallbackToFutureAdapter
.
Nếu muốn thực hiện một số công việc dựa trên lệnh gọi lại không đồng bộ, hãy làm như sau:
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; }); } }
Điều gì sẽ xảy ra nếu công việc của bạn bị dừng? ListenableFuture
của ListenableWorker
luôn bị huỷ khi công việc được dự kiến sẽ ngừng chạy. Khi sử dụng CallbackToFutureAdapter
, bạn chỉ cần thêm trình nghe thao tác huỷ như sau:
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; }); } }
Chạy ListenableWorker trong một quy trình khác
Bạn cũng có thể liên kết một worker với một quy trình cụ thể bằng cách sử dụng RemoteListenableWorker
(một cách triển khai của ListenableWorker
).
RemoteListenableWorker
liên kết với một quy trình cụ thể bằng 2 đối số bổ sung ARGUMENT_CLASS_NAME
và ARGUMENT_PACKAGE_NAME
mà bạn cung cấp dưới dạng một phần của dữ liệu đầu vào khi tạo yêu cầu công việc.
Ví dụ sau đây minh hoạ việc tạo một yêu cầu thực thi công việc ràng buộc với một quy trình cụ thể:
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();
Đối với mỗi RemoteWorkerService
, bạn cũng cần thêm định nghĩa dịch vụ vào tệp 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>