واجهة برمجة التطبيقات Task
هي الطريقة العادية لمعالجة العمليات غير المتزامنة في خدمات
Play من Google. ويقدّم هذا الأسلوب طريقة فعّالة ومرنة لإدارة طلبات PendingResult
غير المتزامنة، ما يحلّ محلّ نمط PendingResult
القديم. باستخدام Task
، يمكنك تسلسل
طلبات متعددة ومعالجة مسارات معقدة وكتابة معالجين واضحَين للنجاح والخطأ.
التعامل مع نتائج المهام
تُعرِض العديد من واجهات برمجة التطبيقات في "خدمات Google Play" وFirebase عنصرًا من النوع Task
لتمثيل العمليات غير المتزامنة. على سبيل المثال، يعرض الرمز
FirebaseAuth.signInAnonymously()
Task<AuthResult>
الذي يمثّل نتيجة عملية تسجيل الدخول. يشير العنصر Task<AuthResult>
إلى أنّه عند اكتمال المهمة
بنجاح، ستُرجِع عنصرًا من النوع AuthResult
.
يمكنك معالجة نتيجة Task
من خلال إرفاق مستمعين يستجيبون لحالة اكتمال العملية بنجاح أو تعذّرها أو كليهما:
Task<AuthResult> task = FirebaseAuth.getInstance().signInAnonymously();
لمعالجة إكمال المهمة بنجاح، يجب إرفاق OnSuccessListener
:
task.addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { // Task completed successfully // ... } });
لحلّ مشكلة تعذُّر إكمال مهمة، يمكنك إرفاق OnFailureListener
:
task.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
لمعالجة كلّ من حالات النجاح والفشل في المستمع نفسه، يمكنك إرفاق
OnCompleteListener
:
task.addOnCompleteListener(new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { if (task.isSuccessful()) { // Task completed successfully AuthResult result = task.getResult(); } else { // Task failed with an exception Exception exception = task.getException(); } } });
إدارة سلاسل المحادثات
يتم تلقائيًا تشغيل مستمعي الأحداث المرتبطين بعنصر Task
في سلسلة المحادثات الرئيسية (واجهة المستخدم)
للتطبيق. وهذا يعني أنّه عليك تجنُّب تنفيذ عمليات تستغرق وقتًا طويلاً في
المستمعين. إذا كنت بحاجة إلى تنفيذ عملية تستغرق وقتًا طويلاً، يمكنك تحديد Executor
يُستخدَم لجدولة المستمعين في سلسلة مهام في الخلفية.
// Create a new ThreadPoolExecutor with 2 threads for each processor on the // device and a 60 second keep-alive time. int numCores = Runtime.getRuntime().availableProcessors(); ThreadPoolExecutor executor = new ThreadPoolExecutor(numCores * 2, numCores *2, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); task.addOnCompleteListener(executor, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { // ... } });
استخدام أدوات الاستماع على مستوى النشاط
عندما تحتاج إلى معالجة نتائج المهام ضمن Activity
، من المهم
إدارة دورة حياة المستمعين لمنع استدعائهم عندما
لم يعُد Activity
مرئيًا. ولإجراء ذلك، يمكنك استخدام أدوات الاستماع على مستوى النشاط. تتم إزالة هذه العناصر المستمعة تلقائيًا عند استدعاء طريقة onStop
في
Activity
، لكي لا يتم تنفيذها بعد stopped
Activity
.
Activity activity = MainActivity.this; task.addOnCompleteListener(activity, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { // ... } });
تسلسل المهام
إذا كنت تستخدم مجموعة من واجهات برمجة التطبيقات التي تعرض كائنات Task
في دالة معقدة،
يمكنك ربطها معًا باستخدام عمليات المتابعة. يساعدك ذلك في تجنُّب طلبات الاستدعاء المُدمجة بشكل عميق وتعزيز معالجة الأخطاء لمهام متعددة متسلسلة.
على سبيل المثال، لنفترض أنّ لديك طريقة doSomething
تؤدي إلى عرض Task<String>
، ولكنّها تتطلّب AuthResult
كمَعلمة.
يمكنك الحصول على هذا AuthResult
بشكل غير متزامن من Task
آخر:
public Task<String> doSomething(AuthResult authResult) { // ... }
باستخدام الطريقة Task.continueWithTask
، يمكنك ربط هاتين المهمتَين:
Task<AuthResult> signInTask = FirebaseAuth.getInstance().signInAnonymously(); signInTask.continueWithTask(new Continuation<AuthResult, Task<String>>() { @Override public Task<String> then(@NonNull Task<AuthResult> task) throws Exception { // Take the result from the first task and start the second one AuthResult result = task.getResult(); return doSomething(result); } }).addOnSuccessListener(new OnSuccessListener<String>() { @Override public void onSuccess(String s) { // Chain of tasks completed successfully, got result from last task. // ... } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // One of the tasks in the chain failed with an exception. // ... } });
حظر مهمة
إذا كان برنامجك قيد التنفيذ في سلسلة مهام في الخلفية، يمكنك حظر السلسلة الحالية والانتظار حتى اكتمال المهمة، بدلاً من استخدام ردّ اتصال:
try { // Block on a task and get the result synchronously. This is generally done // when executing a task inside a separately managed background thread. Doing this // on the main (UI) thread can cause your application to become unresponsive. AuthResult authResult = Tasks.await(task); } catch (ExecutionException e) { // The Task failed, this is the same exception you'd get in a non-blocking // failure handler. // ... } catch (InterruptedException e) { // An interrupt occurred while waiting for the task to complete. // ... }
يمكنك أيضًا تحديد مهلة عند حظر مهمة لمنع تطبيقك من التوقف إلى أجل غير مسمى إذا استغرقت المهمة وقتًا طويلاً لإكمالها:
try { // Block on the task for a maximum of 500 milliseconds, otherwise time out. AuthResult authResult = Tasks.await(task, 500, TimeUnit.MILLISECONDS); } catch (ExecutionException e) { // ... } catch (InterruptedException e) { // ... } catch (TimeoutException e) { // Task timed out before it could complete. // ... }
إمكانية التشغيل التفاعلي
تم تصميم Task
للعمل بشكل جيد مع أنماط برمجة Task
غير المتزامنة الشائعة الأخرى في Android. ويمكن تحويلها إلى عناصر أساسية أخرى والعكس، مثل
ListenableFuture
وعمليات التشغيل المتعدّد للكائنات في Kotlin، والتيينصح بها AndroidX،
ما يتيح لك استخدام النهج الأنسب لاحتياجاتك.
في ما يلي مثال على استخدام Task
:
// ... simpleTask.addOnCompleteListener(this) { completedTask -> textView.text = completedTask.result }
كوروتين Kotlin
لاستخدام الكوروتينات في لغة Kotlin مع Task
، أضِف التبعية التالية إلى
مشروعك، ثم استخدِم مقتطف الرمز البرمجي للتحويل من Task
.
Gradle (build.gradle
على مستوى الوحدة، وعادةً app/build.gradle
)
// Source: https://github.com/Kotlin/kotlinx.coroutines/tree/master/integration/kotlinx-coroutines-play-services implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3'
المقتطف
import kotlinx.coroutines.tasks.await // ... textView.text = simpleTask.await() }
الجوافة ListenableFuture
لاستخدام Guava ListenableFuture
مع Task
، أضِف التبعية التالية إلى
مشروعك، ثم استخدِم مقتطف الرمز البرمجي للتحويل من Task
.
Gradle (build.gradle
على مستوى الوحدة، وعادةً app/build.gradle
)
implementation "androidx.concurrent:concurrent-futures:1.2.0"
المقتطف
import com.google.common.util.concurrent.ListenableFuture // ... /** Convert Task to ListenableFuture. */ fun <T> taskToListenableFuture(task: Task<T>): ListenableFuture<T> { return CallbackToFutureAdapter.getFuture { completer -> task.addOnCompleteListener { completedTask -> if (completedTask.isCanceled) { completer.setCancelled() } else if (completedTask.isSuccessful) { completer.set(completedTask.result) } else { val e = completedTask.exception if (e != null) { completer.setException(e) } else { throw IllegalStateException() } } } } } // ... this.listenableFuture = taskToListenableFuture(simpleTask) this.listenableFuture?.addListener( Runnable { textView.text = listenableFuture?.get() }, ContextCompat.getMainExecutor(this) )
RxJava2 Observable
أضِف التبعية التالية، بالإضافة إلى مكتبة المهام غير المتزامنة النسبية التي تريدها، إلى مشروعك، ثم استخدِم مقتطف الرمز البرمجي للتحويل من Task
.
Gradle (build.gradle
على مستوى الوحدة، وعادةً app/build.gradle
)
// Source: https://github.com/ashdavies/rx-tasks implementation 'io.ashdavies.rx.rxtasks:rx-tasks:2.2.0'
المقتطف
import io.ashdavies.rx.rxtasks.toSingle import java.util.concurrent.TimeUnit // ... simpleTask.toSingle(this).subscribe { result -> textView.text = result }