Bergabunglah bersama kami di ⁠#Android11: The Beta Launch Show pada tanggal 3 Juni!

Threading di ListenableWorker

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 terendah; semua Worker, CoroutineWorker, dan RxWorker 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: ini adalah Future 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 ListenableFuture dengan salah satu dari dua cara berikut:

  1. Jika Anda menggunakan Guava, gunakan ListeningExecutorService.
  2. Jika tidak, sertakan councurrent-futures dalam file gradle Anda dan gunakan CallbackToFutureAdapter.

Jika Anda ingin menjalankan beberapa tugas berdasarkan callback asinkron, Anda harus melakukan hal berikut:

    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.google.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:

    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.google.com", callback);
                }
                return callback;
            });
        }
    }