Task
API adalah cara standar untuk menangani operasi asinkron di layanan
Google Play. API ini menyediakan cara yang efektif dan fleksibel untuk mengelola panggilan
asinkron, yang menggantikan pola PendingResult
lama. Dengan Task
, Anda dapat membuat rantai
beberapa panggilan, menangani alur yang kompleks, dan menulis pengendali
keberhasilan dan kegagalan yang jelas.
Menangani hasil tugas
Banyak API di layanan Google Play dan Firebase menampilkan objek Task
untuk
mewakili operasi asinkron. Misalnya,
FirebaseAuth.signInAnonymously()
menampilkan Task<AuthResult>
yang mewakili hasil operasi
login. Task<AuthResult>
menunjukkan bahwa saat tugas berhasil
selesai, tugas akan menampilkan objek AuthResult
.
Anda dapat menangani hasil Task
dengan melampirkan pemroses yang merespons
penyelesaian yang berhasil, kegagalan, atau keduanya:
Task<AuthResult> task = FirebaseAuth.getInstance().signInAnonymously();
Untuk menangani penyelesaian tugas yang berhasil, lampirkan OnSuccessListener
:
task.addOnSuccessListener(new OnSuccessListener<AuthResult>() { @Override public void onSuccess(AuthResult authResult) { // Task completed successfully // ... } });
Untuk menangani tugas yang gagal, lampirkan OnFailureListener
:
task.addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
Untuk menangani keberhasilan dan kegagalan di pemroses yang sama, lampirkan
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(); } } });
Mengelola rangkaian pesan
Secara default, pemroses yang dilampirkan ke Task
dijalankan di thread utama (UI)
aplikasi. Artinya, Anda harus menghindari melakukan operasi yang berjalan lama di
pemroses. Jika perlu melakukan operasi yang berjalan lama, Anda dapat menentukan
Executor
yang digunakan untuk menjadwalkan pemroses di thread latar belakang.
// 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) { // ... } });
Menggunakan pemroses cakupan aktivitas
Jika Anda perlu menangani hasil tugas dalam Activity
, penting untuk
mengelola siklus proses pemroses untuk mencegahnya dipanggil saat
Activity
tidak lagi terlihat. Untuk melakukannya, Anda dapat menggunakan pemroses
cakupan aktivitas. Pemroses ini akan otomatis dihapus saat metode onStop
Activity
Anda dipanggil, sehingga tidak akan dieksekusi setelah
Activity
dihentikan.
Activity activity = MainActivity.this; task.addOnCompleteListener(activity, new OnCompleteListener<AuthResult>() { @Override public void onComplete(@NonNull Task<AuthResult> task) { // ... } });
Menautkan tugas
Jika menggunakan kumpulan API yang menampilkan objek Task
dalam fungsi yang kompleks,
Anda dapat merantainya menggunakan kelanjutan. Hal ini membantu Anda menghindari callback yang
tumpang-tindih dan menggabungkan penanganan error untuk beberapa tugas berantai.
Misalnya, pertimbangkan skenario saat Anda memiliki metode doSomething
yang
menampilkan Task<String>
, tetapi memerlukan AuthResult
sebagai parameter.
Anda dapat memperoleh AuthResult
ini secara asinkron dari Task
lain:
public Task<String> doSomething(AuthResult authResult) { // ... }
Dengan menggunakan metode Task.continueWithTask
, Anda dapat merantai dua tugas ini:
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. // ... } });
Memblokir tugas
Jika program sudah dieksekusi di thread latar belakang, Anda dapat memblokir thread saat ini dan menunggu tugas selesai, bukan menggunakan callback:
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. // ... }
Anda juga dapat menentukan waktu tunggu saat memblokir tugas untuk mencegah aplikasi Anda macet tanpa batas jika tugas memerlukan waktu terlalu lama untuk diselesaikan:
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. // ... }
Interoperabilitas
Task
dirancang agar berfungsi dengan baik dengan pola pemrograman asinkron
Android umum lainnya. Fungsi ini dapat dikonversi ke dan dari primitif lain seperti
ListenableFuture
dan coroutine Kotlin, yang
direkomendasikan oleh AndroidX,
sehingga Anda dapat menggunakan pendekatan yang paling sesuai dengan kebutuhan Anda.
Berikut adalah contoh yang menggunakan Task
:
// ... simpleTask.addOnCompleteListener(this) { completedTask -> textView.text = completedTask.result }
Coroutine Kotlin
Untuk menggunakan coroutine Kotlin dengan Task
, tambahkan dependensi berikut ke
project Anda, lalu gunakan cuplikan kode untuk mengonversi dari Task
.
Gradle (build.gradle
level modul, biasanya 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'
Cuplikan
import kotlinx.coroutines.tasks.await // ... textView.text = simpleTask.await() }
Guava ListenableFuture
Untuk menggunakan Guava ListenableFuture
dengan Task
, tambahkan dependensi berikut ke
project Anda, lalu gunakan cuplikan kode untuk mengonversi dari Task
.
Gradle (build.gradle
level modul, biasanya app/build.gradle
)
implementation "androidx.concurrent:concurrent-futures:1.2.0"
Cuplikan
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
Tambahkan dependensi berikut, selain library asinkron relatif
pilihan, ke project Anda, lalu gunakan cuplikan kode untuk mengonversi dari Task
.
Gradle (build.gradle
level modul, biasanya app/build.gradle
)
// Source: https://github.com/ashdavies/rx-tasks implementation 'io.ashdavies.rx.rxtasks:rx-tasks:2.2.0'
Cuplikan
import io.ashdavies.rx.rxtasks.toSingle import java.util.concurrent.TimeUnit // ... simpleTask.toSingle(this).subscribe { result -> textView.text = result }