سلسلة المحادثات في ListenableWorker

في بعض الحالات، قد تحتاج إلى تقديم استراتيجية مخصّصة لسلاسل المحادثات. على سبيل المثال، قد تحتاج إلى التعامل مع عملية غير متزامنة قائمة على معاودة الاتصال. يدعم WorkManager حالة الاستخدام هذه مع ListenableWorker. ListenableWorker هي أبسط واجهة برمجة تطبيقات للعاملين، وتشمل Worker وCoroutineWorker وRxWorker كل ذلك من هذه الفئة. لا يشير ListenableWorker إلا إلى الوقت الذي يجب أن يبدأ فيه العمل ويتوقف عنده ويترك سلسلة المحادثات متروكة لك تمامًا. يتم استدعاء إشارة بدء العمل على سلسلة التعليمات الرئيسية، لذا من المهم جدًا أن تنتقل إلى سلسلة رسائل خلفية من اختيارك يدويًا.

تعرض طريقة التجريد ListenableWorker.startWork() ListenableFuture من Result. واجهة ListenableFuture هي واجهة بسيطة: وهي واجهة Future توفِّر وظائف لإرفاق أدوات معالجة البيانات ونشر الاستثناءات. في طريقة startWork، من المتوقّع أن تعرض ListenableFuture الذي ستضبطه مع Result للعملية بعد اكتمالها. يمكنك إنشاء ListenableFuture مثيل بإحدى الطريقتين التاليتين:

  1. إذا كنت تستخدم Guava، استخدم ListeningExecutorService.
  2. بخلاف ذلك، يمكنك تضمين councurrent-futures في ملف Grale واستخدام 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;
        });
    }
}

ماذا يحدث في حال إيقاف عملك؟ يتم دائمًا إلغاء تفويض ListenableFuture لـ "ListenableWorker" عندما يكون من المتوقّع أن يتوقف العمل. وباستخدام 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 في عملية مختلفة

يمكنك أيضًا إلزام العامل بعملية محدّدة باستخدام RemoteListenableWorker، وهي تنفيذ ListenableWorker.

ترتبط السمة RemoteListenableWorker بعملية محدّدة باستخدام وسيطتين إضافيتين تقدّمهما كجزء من بيانات الإدخال عند إنشاء طلب العمل، وهما: ARGUMENT_CLASS_NAME وARGUMENT_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>

عيّنات