Tasks API

Mulai layanan Google Play versi 9.0.0, Anda dapat menggunakan Task API dan jumlah metode yang menampilkan Task atau subclass-nya. Task adalah API yang mewakili panggilan metode asinkron, mirip dengan PendingResult di versi terbaru dari layanan Google Play.

Menangani hasil tugas

Metode umum yang menampilkan Task adalah FirebaseAuth.signInAnonymously(). Metode ini menampilkan Task<AuthResult> yang berarti tugas akan ditampilkan objek AuthResult saat berhasil:

Task<AuthResult> task = FirebaseAuth.getInstance().signInAnonymously();

Agar diberi tahu saat tugas berhasil, lampirkan OnSuccessListener:

task.addOnSuccessListener(new OnSuccessListener<AuthResult>() {
    @Override
    public void onSuccess(AuthResult authResult) {
        // Task completed successfully
        // ...
    }
});

Agar mendapatkan notifikasi saat tugas 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, instal 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();
        }
    }
});

Threading

Pemroses yang dilampirkan ke thread dijalankan di thread utama aplikasi (UI) secara {i>default<i}. Saat menambahkan pemroses, Anda juga dapat menentukan Executor yang digunakan untuk menjadwalkan pemroses.

// 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) {
        // ...
    }
});

Pemroses dengan cakupan aktivitas

Jika Anda memproses hasil tugas di Activity, Anda mungkin perlu menambahkan pemroses cakupan aktivitas ke tugas. Pemroses ini dihapus selama metode onStop Aktivitas sehingga pemroses tidak dipanggil saat Aktivitas tidak lagi terlihat.

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

Perantaian

Jika menggunakan beberapa API yang menampilkan Task, Anda dapat menggabungkannya menggunakan kelanjutan. Hal ini membantu menghindari callback bertingkat yang dalam dan penggabungan penanganan {i>error<i} untuk rantai tugas.

Misalnya, metode doSomething menampilkan Task<String>, tetapi memerlukan AuthResult, yang akan kita dapatkan secara asinkron dari tugas:

public Task<String> doSomething(AuthResult authResult) {
    // ...
}

Dengan menggunakan metode Task.continueWithTask, kita dapat membuat rantai 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.
        // ...
    }
});

Pemblokiran

Jika program Anda sudah dieksekusi di thread latar belakang, Anda bisa memblokir tugas untuk mendapatkan hasil secara sinkron dan menghindari 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 sehingga aplikasi Anda tidak hang:

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

Secara konseptual, Task selaras dengan beberapa pendekatan Android populer untuk mengelola kode asinkron, dan Task dapat langsung dikonversi ke skrip dasar, termasuk coroutine ListenableFuture dan Kotlin, yang direkomendasikan oleh AndroidX.

Berikut adalah contoh penggunaan Task:

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

Coroutine Kotlin

Penggunaan

Tambahkan dependensi berikut ke project Anda dan gunakan kode di bawah ini 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()
}

ListenableFuture dari Guava

Tambahkan dependensi berikut ke project Anda dan gunakan kode di bawah ini 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 Dapat Diobservasi

Tambahkan dependensi berikut, selain library asinkron relatif ke project Anda dan gunakan kode di bawah ini 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 }

Langkah berikutnya