واجهة برمجة التطبيقات "مهام Google"

بدءًا من الإصدار 9.0.0 من "خدمات Google Play"، يمكنك استخدام واجهة برمجة تطبيقات Task وعدد من الطرق التي تعرض Task أو فئاته الفرعية. Task هي واجهة برمجة تطبيقات تمثّل طلبات إجراء غير متزامنة، على غرار PendingResult في الإصدارات السابقة من "خدمات Google Play".

التعامل مع نتائج المهام

هناك طريقة شائعة تعرض Task هي FirebaseAuth.signInAnonymously(). وتعرض المهمة Task<AuthResult>، ما يعني أنّ المهمة ستعرض كائن AuthResult عندما تنجح:

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();
        }
    }
});

خيوط

يتم تشغيل أدوات معالجة البيانات المرفقة بسلسلة محادثات على سلسلة المحادثات الرئيسية للتطبيق (واجهة المستخدم) بشكلٍ تلقائي. عند إرفاق مستمِع، يمكنك أيضًا تحديد 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، قد تحتاج إلى إضافة مستمعين على مستوى النشاط إلى المهمة. وتتم إزالة أدوات معالجة البيانات هذه عند استخدام طريقة onStop لنشاطك، وبالتالي لا يتم استدعاء المستمعين عندما لا يعود النشاط مرئيًا.

Activity activity = MainActivity.this;
task.addOnCompleteListener(activity, new OnCompleteListener<AuthResult>() {
    @Override
    public void onComplete(@NonNull Task<AuthResult> task) {
        // ...
    }
});

السلاسل

إذا كنت تستخدم واجهات برمجة تطبيقات متعددة تعرض السمة Task، يمكنك ربطها معًا باتّباع الخطوات التالية: يساعد هذا في تجنب استدعاءات المكالمات المتداخلة بشدة ودمج معالجة الأخطاء لسلاسل المهام.

على سبيل المثال، تعرض الطريقة doSomething Task<String> ولكنها تتطلّب AuthResult، والتي سنحصل عليها بشكل غير متزامن من المهمة:

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 من الناحية النظرية مع العديد من أساليب Android الشائعة لإدارة الرمز البرمجي غير المتزامن، ويمكن تحويل Task مباشرةً إلى تنسيقات أولية أخرى، بما في ذلك الكوروتينات ListenableFuture وKotlin، والتي يوصي بها AndroidX.

إليك مثال على استخدام السمة Task:

// ...
simpleTask.addOnCompleteListener(this) {
  completedTask -> textView.text = completedTask.result
}

كوروتين بلغة Kotlin

الاستخدام

أضِف الاعتمادية التالية إلى مشروعك واستخدِم الرمز أدناه للتحويل من 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.4.1'
المقتطف
import kotlinx.coroutines.tasks.await
// ...
  textView.text = simpleTask.await()
}

مستقبل استماع جوفا

أضِف الاعتمادية التالية إلى مشروعك واستخدِم الرمز أدناه للتحويل من Task.

Gradle (build.gradle على مستوى الوحدة، عادةً app/build.gradle)
implementation "androidx.concurrent:concurrent-futures:1.1.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 يمكن ملاحظته

أضِف الاعتمادية التالية إلى مشروعك، بالإضافة إلى المكتبة النسبية غير المتزامنة التي اخترتها، واستخدِم الرمز أدناه للتحويل من 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 }

الخطوات التالية