واجهة برمجة التطبيقات "مهام 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()
}

قناة Guava ListenableFuture

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

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