Tasks API

با شروع خدمات Google Play نسخه 9.0.0، می‌توانید از Task API و تعدادی از روش‌هایی که Task یا زیر کلاس‌های آن را برمی‌گردانند استفاده کنید. Task یک API است که شبیه به 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();
        }
    }
});

نخ زنی

شنوندگان متصل به یک رشته به طور پیش فرض بر روی رشته اصلی برنامه (UI) اجرا می شوند. هنگام پیوست کردن شنونده، می توانید یک 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 دیگر قابل مشاهده نیست، شنوندگان شما فراخوانی نشوند.

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

زنجیر زدن

اگر از چندین API استفاده می‌کنید که 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
}

کاتلین کوروتین

استفاده

وابستگی زیر را به پروژه خود اضافه کنید و از کد زیر برای تبدیل از یک 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 }

مراحل بعدی