Task
API روشی استاندارد برای مدیریت عملیات ناهمزمان در خدمات Google Play است. این روشی قدرتمند و انعطافپذیر برای مدیریت تماسهای ناهمزمان ارائه میکند و جایگزین الگوی قدیمیتر PendingResult
میشود. با Task
میتوانید چندین تماس را زنجیرهای کنید، جریانهای پیچیده را مدیریت کنید، و کنترلکنندههای موفقیت و شکست را واضح بنویسید.
رسیدگی به نتایج کار
بسیاری از APIها در سرویسهای 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
در رشته اصلی برنامه (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
مدیریت کنید، مهم است که چرخه عمر شنوندگان را مدیریت کنید تا از فراخوانی آنها در زمانی که 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
نیاز دارد. می توانید این 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
به گونه ای طراحی شده است که با سایر الگوهای برنامه نویسی ناهمزمان رایج اندروید به خوبی کار کند. میتوان آن را به و از دیگر موارد اولیه مانند ListenableFuture
و Kotlin که توسط AndroidX توصیه میشود، تبدیل کرد و به شما امکان میدهد از رویکردی استفاده کنید که به بهترین وجه با نیازهای شما مطابقت دارد.
در اینجا یک مثال با استفاده از Task
آورده شده است:
// ... simpleTask.addOnCompleteListener(this) { completedTask -> textView.text = completedTask.result }
کاتلین کوروتین
برای استفاده از کوروتین های 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() }
Guava 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 }