Ada banyak opsi di Android untuk pekerjaan latar belakang yang dapat ditangguhkan. Codelab ini mencakup WorkManager, library sederhana yang kompatibel dan fleksibel untuk pekerjaan latar belakang yang dapat ditangguhkan. WorkManager adalah penjadwal tugas yang direkomendasikan di Android untuk pekerjaan yang dapat ditangguhkan, dan dijamin akan dieksekusi.
Apa WorkManager itu
WorkManager adalah bagian dari Android Jetpack dan Komponen Arsitektur untuk pekerjaan latar belakang yang memerlukan kombinasi eksekusi oportunistik dan terjamin. Eksekusi oportunistik berarti WorkManager akan melakukan pekerjaan latar belakang Anda sesegera mungkin. Eksekusi terjamin berarti WorkManager akan menangani logika untuk memulai pekerjaan dalam berbagai situasi, meskipun Anda keluar dari aplikasi.
WorkManager adalah library sederhana, namun sangat fleksibel yang memiliki banyak manfaat tambahan. Ini mencakup:
- Dukungan untuk tugas satu kali atau berkala asinkron
- Dukungan untuk batasan seperti kondisi jaringan, ruang penyimpanan, dan status pengisian daya
- Merangkai permintaan pekerjaan yang kompleks, termasuk menjalankan pekerjaan secara paralel
- Output dari satu permintaan pekerjaan digunakan sebagai input untuk permintaan berikutnya
- Menangani kompatibilitas API level kembali ke API level 14 (lihat catatan)
- Berfungsi dengan atau tanpa layanan Google Play
- Mengikuti praktik terbaik kesehatan sistem
- Dukungan LiveData agar dapat dengan mudah menampilkan status permintaan pekerjaan di UI
Kapan harus menggunakan WorkManager
Library WorkManager adalah pilihan tepat untuk tugas yang berguna untuk diselesaikan, bahkan jika pengguna keluar dari layar tertentu atau aplikasi Anda.
Beberapa contoh tugas yang menggunakan WorkManager dengan baik:
- Mengupload log
- Menerapkan filter ke gambar dan menyimpan gambar
- Menyinkronkan data lokal dengan jaringan secara berkala
WorkManager menawarkan eksekusi terjamin, dan tidak semua tugas memerlukannya. Dengan demikian, tidak semua tugas akan dijalankan di thread utama. Untuk detail selengkapnya tentang kapan harus menggunakan WorkManager, lihat Panduan pemrosesan latar belakang.
Yang akan Anda build
Saat ini, smartphone hampir sempurna dalam mengambil gambar. Lewatlah sudah hari-hari saat seorang fotografer dapat mengambil gambar yang cukup buram dari sesuatu yang misterius.
Dalam codelab ini, Anda akan menjalankan Blur-O-Matic, sebuah aplikasi untuk memburamkan foto dan gambar serta menyimpan hasilnya ke file. Apakah itu monster Loch Ness atau kapal selam mainan evelopera? Dengan Blur-O-Matic, tidak akan ada yang tahu.
Foto ikan kakap bergaris hibrida oleh Peggy Greb, USDA Agricultural Research Service. |
Yang akan Anda pelajari
- Menambahkan WorkManager ke project Anda
- Menjadwalkan tugas sederhana
- Parameter input dan output
- Perantaian pekerjaan
- Pekerjaan unik
- Menampilkan status pekerjaan di UI
- Membatalkan pekerjaan
- Batasan pekerjaan
Yang Anda butuhkan
- Versi Android Studio terbaru yang stabil
- Anda juga harus memahami
LiveData
danViewModel
. Jika Anda masih baru di class ini, lihat Codelab komponen berbasis Siklus Proses Android (khusus untuk ViewModel dan LiveData) atau Room dengan Codelab View (pengantar Komponen Arsitektur).
Jika Anda mengalami masalah pada tahap tertentu...
Jika Anda mengalami masalah dengan codelab di tahap tertentu, atau jika Anda ingin melihat status akhir kode, Anda dapat menggunakan link berikut:
Atau jika mau, Anda dapat meng-clone codelab WorkManager yang telah selesai dari GitHub:
$ git clone -b java https://github.com/googlecodelabs/android-workmanager
Langkah 1 - Download Kode
Klik link berikut guna mendownload semua kode untuk codelab ini:
Atau jika mau, Anda dapat meng-clone codelab navigasi dari GitHub:
$ git clone -b start_java https://github.com/googlecodelabs/android-workmanager
Langkah 2 - Dapatkan Gambar
Jika Anda menggunakan perangkat yang telah mendownload atau mengambil gambar di perangkat, berarti Anda telah siap.
Jika Anda menggunakan perangkat baru (seperti emulator yang baru dibuat), sebaiknya ambil gambar atau download gambar dari web menggunakan perangkat. Pilih sesuatu yang misterius.
Langkah 3 - Jalankan aplikasi
Jalankan aplikasi. Anda akan melihat layar berikut (pastikan Anda memberikan izin untuk mengakses foto dari perintah awal dan jika gambar dinonaktifkan, buka kembali aplikasi):
Anda dapat memilih gambar dan membuka layar berikutnya yang memiliki tombol pilihan. Di layar tersebut, Anda dapat menentukan tingkat keburaman gambar. Menekan tombol Go pada akhirnya akan memburamkan dan menyimpan gambar.
Sekarang, aplikasi tidak menerapkan efek buram.
Kode awal berisi:
WorkerUtils
**:** Class ini berisi kode untuk pemburaman yang sebenarnya, dan beberapa metode praktis yang nantinya akan digunakan untuk menampilkanNotifications
dan memperlambat aplikasi.BlurActivity
***:** Aktivitas yang menampilkan gambar dan menyertakan tombol pilihan untuk memilih tingkat keburaman.BlurViewModel
***:** Model tampilan ini menyimpan semua data yang diperlukan untuk menampilkanBlurActivity
. Kode ini juga akan menjadi class tempat Anda memulai pekerjaan latar belakang menggunakan WorkManager.Constants
**:** Class statis dengan beberapa konstanta yang akan Anda gunakan selama codelab.SelectImageActivity
**:** Aktivitas pertama yang memungkinkan Anda untuk memilih gambar.res/activity_blur.xml
danres/activity_select.xml
: File tata letak untuk setiap aktivitas.
***** Ini adalah satu-satunya file tempat Anda menuliskan kode.
WorkManager
memerlukan dependensi gradle di bawah ini. Dependensi ini sudah disertakan dalam file build:
app/build.gradle
dependencies {
// Other dependencies
implementation "androidx.work:work-runtime:$versions.work"
}
Anda harus mendapatkan versi terbaru work-runtime
dari sini dan menempatkan versi yang benar. Untuk saat ini, versi terbaru adalah:
build.gradle
versions.work = "2.3.3"
Jika Anda mengupdate versi ke yang lebih baru, pastikan untuk memilih Sync Now guna menyinkronkan project Anda dengan file gradle yang diubah.
Pada langkah ini, Anda akan mengambil gambar di folder res/drawable
bernama test.jpg
dan menjalankan beberapa fungsi di dalamnya di latar belakang. Fungsi ini akan memburamkan gambar dan menyimpannya ke file sementara.
Dasar-dasar WorkManager
Ada beberapa class WorkManager yang perlu Anda ketahui:
Worker
: Ini adalah tempat Anda menempatkan kode untuk pekerjaan yang sebenarnya yang ingin Anda lakukan di latar belakang. Anda akan memperluas class ini dan mengganti metodedoWork()
.WorkRequest
: Ini mewakili permintaan untuk melakukan beberapa pekerjaan. Anda akan meneruskanWorker
sebagai bagian dari pembuatanWorkRequest
. Saat membuatWorkRequest
, Anda juga dapat menentukan hal-hal sepertiConstraints
terkait kapanWorker
harus dijalankan.WorkManager
: Class ini sebenarnya menjadwalkanWorkRequest
Anda dan menjalankannya. Class ini menjadwalkanWorkRequest
dengan cara menyebarkan beban pada resource sistem, sekaligus memenuhi batasan yang Anda tetapkan.
Dalam kasus ini, Anda akan menentukan BlurWorker
baru yang akan berisi kode untuk memburamkan gambar. Saat tombol Go diklik, WorkRequest
akan dibuat lalu diantrekan oleh WorkManager
.
Langkah 1 - Buat BlurWorker
Pada paket workers
, buat class baru bernama BlurWorker
.
Class ini harus memperluas Worker
.
Langkah 2 - Tambahkan konstruktor
Tambahkan konstruktor ke class BlurWorker
:
public class BlurWorker extends Worker {
public BlurWorker(
@NonNull Context appContext,
@NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
}
Langkah 3 - Ganti dan implementasikan doWork()
Worker
Anda akan memburamkan gambar res/test.jpg
.
Ganti metode doWork()
, lalu implementasikan hal berikut:
- Dapatkan
Context
dengan memanggilgetApplicationContext()
. Anda akan memerlukan ini untuk berbagai manipulasi bitmap yang akan Anda lakukan. - Buat
Bitmap
dari gambar pengujian:
Bitmap picture = BitmapFactory.decodeResource(
applicationContext.getResources(),
R.drawable.test);
- Dapatkan versi buram bitmap dengan memanggil metode
blurBitmap
statis dariWorkerUtils
. - Tulis bitmap tersebut ke file sementara dengan memanggil metode
writeBitmapToFile
statis dariWorkerUtils
. Pastikan untuk menyimpan URI yang ditampilkan ke variabel lokal. - Buat Notifikasi yang menampilkan URI dengan memanggil metode
makeStatusNotification
statis dariWorkerUtils
. - Tampilkan
Result.success();
- Gabungkan kode dari langkah 2-6 dalam pernyataan try/catch. Tangkap
Throwable
generik. - Dalam pernyataan catch, tampilkan Laporan log error:
Log.e(TAG, "Error applying blur", throwable);
- Dalam pernyataan catch, tampilkan
Result.failure();
Kode yang sudah selesai untuk langkah ini ada di bawah.
BlurWorker.java
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import com.example.background.R;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
public class BlurWorker extends Worker {
public BlurWorker(
@NonNull Context appContext,
@NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
private static final String TAG = BlurWorker.class.getSimpleName();
@NonNull
@Override
public Result doWork() {
Context applicationContext = getApplicationContext();
try {
Bitmap picture = BitmapFactory.decodeResource(
applicationContext.getResources(),
R.drawable.test);
// Blur the bitmap
Bitmap output = WorkerUtils.blurBitmap(picture, applicationContext);
// Write bitmap to a temp file
Uri outputUri = WorkerUtils.writeBitmapToFile(applicationContext, output);
WorkerUtils.makeStatusNotification("Output is "
+ outputUri.toString(), applicationContext);
// If there were no errors, return SUCCESS
return Result.success();
} catch (Throwable throwable) {
// Technically WorkManager will return Result.failure()
// but it's best to be explicit about it.
// Thus if there were errors, we're return FAILURE
Log.e(TAG, "Error applying blur", throwable);
return Result.failure();
}
}
}
Langkah 4 - Dapatkan WorkManager di ViewModel
Buat variabel untuk instance WorkManager
di ViewModel
dan buat instance di konstruktor ViewModel
:
BlurViewModel.java
private WorkManager mWorkManager;
// BlurViewModel constructor
public BlurViewModel(@NonNull Application application) {
super(application);
mWorkManager = WorkManager.getInstance(application);
//...rest of the constructor
}
Langkah 5 - Antrekan WorkRequest di WorkManager
Baik, saatnya membuat WorkRequest dan memberi tahu WorkManager untuk menjalankannya. Ada dua jenis WorkRequest
:
OneTimeWorkRequest:
WorkRequest
yang hanya akan dieksekusi satu kali.PeriodicWorkRequest:
WorkRequest
yang akan diulang pada siklus.
Kita hanya ingin gambar diburamkan satu kali saat tombol Go diklik. Metode applyBlur
dipanggil saat tombol Go diklik, jadi buat OneTimeWorkRequest
dari BlurWorker
di sana. Lalu, gunakan instance WorkManager
untuk mengantrekan WorkRequest.
Tambahkan baris kode berikut ke metode applyBlur() BlurViewModel
:
BlurViewModel.java
void applyBlur(int blurLevel) {
mWorkManager.enqueue(OneTimeWorkRequest.from(BlurWorker.class));
}
Langkah 6 - Jalankan kode Anda.
Jalankan kode. Kode harus mengompilasi dan Anda akan melihat Notifikasi saat Anda menekan tombol Go.
Anda juga dapat membuka Device File Explorer di Android Studio:
Lalu buka data>data>com.example.background>files>blur_filter_outputs><URI> dan pastikan bahwa ikan tersebut sudah diburamkan:
Pemburaman gambar pengujian sudah berhasil, tetapi agar Blur-O-Matic benar-benar menjadi aplikasi pengeditan gambar yang revolusioner seperti yang diharapkan, Anda harus mengizinkan pengguna memburamkan gambar mereka sendiri.
Untuk melakukannya, kita akan memberikan URI gambar pilihan pengguna sebagai input ke WorkRequest
.
Langkah 1 - Buat Objek input data
Input dan output diteruskan ke dan dikeluarkan melalui objek Data
. Objek Data
adalah container ringan untuk key-value pair. Objek tersebut dimaksudkan untuk menyimpan sejumlah kecil data yang dapat diteruskan ke dan keluar dari WorkRequest
.
Anda akan meneruskan URI untuk gambar pengguna ke dalam paket. URI tersebut disimpan dalam variabel bernama mImageUri
.
Buat metode pribadi bernama createInputDataForUri
. Metode ini harus:
- Membuat objek
Data.Builder
. - Jika
mImageUri
bukanURI
non-null, tambahkan ke objekData
menggunakan metodeputString
. Metode ini mengambil kunci dan nilai. Anda dapat menggunakan konstanta StringKEY_IMAGE_URI
dari classConstants
. - Panggil
build()
pada objekData.Builder
untuk membuat objekData
Anda, lalu menampilkannya.
Berikut adalah metode createInputDataForUri
yang telah selesai:
BlurViewModel.java
/**
* Creates the input data bundle which includes the Uri to operate on
* @return Data which contains the Image Uri as a String
*/
private Data createInputDataForUri() {
Data.Builder builder = new Data.Builder();
if (mImageUri != null) {
builder.putString(KEY_IMAGE_URI, mImageUri.toString());
}
return builder.build();
}
Langkah 2 - Teruskan Objek data ke WorkRequest
Anda akan mengubah metode applyBlur
sehingga:
- Membuat
OneTimeWorkRequest.Builder
baru. - Memanggil
setInputData
, meneruskan hasil daricreateInputDataForUri
. - Mem-build
OneTimeWorkRequest
. - Mengantrekan permintaan tersebut menggunakan
WorkManager
.
Berikut adalah metode applyBlur
yang telah selesai:
BlurViewModel.java
void applyBlur(int blurLevel) {
OneTimeWorkRequest blurRequest =
new OneTimeWorkRequest.Builder(BlurWorker.class)
.setInputData(createInputDataForUri())
.build();
mWorkManager.enqueue(blurRequest);
}
Langkah 3 - Perbarui doWork() BlurWorker untuk mendapatkan input
Sekarang mari kita perbarui metode doWork()
BlurWorker
untuk mendapatkan URI yang kita teruskan dari objek Data
:
BlurWorker.java
public Result doWork() {
Context applicationContext = getApplicationContext();
// ADD THIS LINE
String resourceUri = getInputData().getString(Constants.KEY_IMAGE_URI);
//... rest of doWork()
}
Variabel ini tidak digunakan sampai Anda menyelesaikan langkah berikutnya.
Langkah 4 - Buramkan URI yang ditentukan
Dengan URI, Anda dapat memburamkan gambar yang dipilih pengguna:
BlurWorker.java
public Worker.Result doWork() {
Context applicationContext = getApplicationContext();
String resourceUri = getInputData().getString(Constants.KEY_IMAGE_URI);
try {
// REPLACE THIS CODE:
// Bitmap picture = BitmapFactory.decodeResource(
// applicationContext.getResources(),
// R.drawable.test);
// WITH
if (TextUtils.isEmpty(resourceUri)) {
Log.e(TAG, "Invalid input uri");
throw new IllegalArgumentException("Invalid input uri");
}
ContentResolver resolver = applicationContext.getContentResolver();
// Create a bitmap
Bitmap picture = BitmapFactory.decodeStream(
resolver.openInputStream(Uri.parse(resourceUri)));
//...rest of doWork
Langkah 5 - Buat output URI sementara
Kita sudah selesai dengan Pekerja ini, dan sekarang kita dapat menampilkan Result.success()
. Kita akan menyediakan OutputURI sebagai Data output agar gambar sementara ini dapat diakses dengan mudah oleh pekerja lain untuk operasi selanjutnya. Hal ini akan berguna dalam bab berikutnya saat kita membuat Rantai pekerja. Untuk melakukan ini:
- Buat
Data
baru, seperti yang Anda lakukan dengan input, dan simpanoutputUri
sebagaiString
. Gunakan kunci yang sama,KEY_IMAGE_URI
- Teruskan ini ke metode
Result.success()
Worker
.
BlurWorker.java
Baris ini harus mengikuti baris WorkerUtils.makeStatusNotification
dan mengganti Result.success()
di doWork()
:
Data outputData = new Data.Builder()
.putString(KEY_IMAGE_URI, outputUri.toString())
.build();
return Result.success(outputData);
Langkah 6 - Jalankan aplikasi Anda
Pada tahap ini, Anda dapat menjalankan aplikasi. Aplikasi harus mengompilasi dan memiliki perilaku yang sama.
Anda juga dapat membuka Device File Explorer di Android Studio dan menavigasikan ke data/data/com.example.background/files/blur_filter_outputs/<URI> seperti yang Anda lakukan di langkah sebelumnya.
Perhatikan bahwa Anda mungkin perlu memilih Synchronize untuk melihat gambar Anda:
Bagus sekali! Anda berhasil memburamkan gambar input menggunakan WorkManager
.
Saat ini, Anda sedang melakukan satu tugas pekerjaan: memburamkan gambar. Pekerjaan ini adalah langkah pertama yang bagus, tetapi tidak memiliki beberapa fungsi inti:
- Pekerjaan ini tidak membersihkan file sementara.
- Pekerjaan ini tidak benar-benar menyimpan gambar ke file permanen.
- Pekerjaan ini selalu memburamkan gambar dengan jumlah yang sama.
Kita akan menggunakan rantai pekerjaan WorkManager untuk menambahkan fungsi ini.
WorkManager memungkinkan Anda membuat WorkerRequest
terpisah yang berjalan sesuai urutan atau paralel. Pada langkah ini, Anda akan membuat rantai pekerjaan yang terlihat seperti ini:
WorkRequest
digambarkan sebagai kotak.
Fitur lain yang benar-benar bagus dari perantaian adalah output dari satu WorkRequest
menjadi input dari WorkRequest
berikutnya dalam rantai. Input dan output yang diteruskan di antara setiap WorkRequest
ditampilkan sebagai teks biru.
Langkah 1 - Buat Pembersihan dan Simpan Pekerja
Pertama, Anda akan menentukan semua class Worker
yang dibutuhkan. Anda sudah memiliki Worker
untuk memburamkan gambar, tetapi Anda juga memerlukan Worker
yang membersihkan file sementara dan Worker
yang menyimpan gambar secara permanen.
Buat dua class baru di paket worker
yang memperluas Worker
.
Class pertama harus disebut CleanupWorker
, class kedua harus disebut SaveImageToFileWorker
.
Langkah 2 - Tambahkan konstruktor
Tambahkan konstruktor ke class CleanupWorker
:
public class CleanupWorker extends Worker {
public CleanupWorker(
@NonNull Context appContext,
@NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
}
Langkah 3 - Ganti dan implementasikan doWork() untuk CleanupWorker
CleanupWorker
tidak perlu mengambil input apa pun atau meneruskan output apa pun. Pekerja ini selalu menghapus file sementara jika ada. Karena ini bukan codelab tentang manipulasi file, Anda dapat menyalin kode untuk CleanupWorker
di bawah ini:
CleanupWorker.java
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.example.background.Constants;
import java.io.File;
public class CleanupWorker extends Worker {
public CleanupWorker(
@NonNull Context appContext,
@NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
private static final String TAG = CleanupWorker.class.getSimpleName();
@NonNull
@Override
public Result doWork() {
Context applicationContext = getApplicationContext();
// Makes a notification when the work starts and slows down the work so that it's easier to
// see each WorkRequest start, even on emulated devices
WorkerUtils.makeStatusNotification("Cleaning up old temporary files",
applicationContext);
WorkerUtils.sleep();
try {
File outputDirectory = new File(applicationContext.getFilesDir(),
Constants.OUTPUT_PATH);
if (outputDirectory.exists()) {
File[] entries = outputDirectory.listFiles();
if (entries != null && entries.length > 0) {
for (File entry : entries) {
String name = entry.getName();
if (!TextUtils.isEmpty(name) && name.endsWith(".png")) {
boolean deleted = entry.delete();
Log.i(TAG, String.format("Deleted %s - %s",
name, deleted));
}
}
}
}
return Worker.Result.success();
} catch (Exception exception) {
Log.e(TAG, "Error cleaning up", exception);
return Worker.Result.failure();
}
}
}
Langkah 4 - Ganti dan implementasikan doWork() untuk SaveImageToFileWorker
SaveImageToFileWorker
akan mengambil input dan output. Inputnya adalah String
yang disimpan dengan kunci KEY_IMAGE_URI
. Dan outputnya juga String
yang disimpan dengan kunci KEY_IMAGE_URI
.
Karena codelab ini belum membahas manipulasi file, kodenya ada di bawah ini, berisi dua TODO
untuk Anda guna mengisi kode yang sesuai untuk input dan output. Ini sangat mirip dengan kode yang Anda tulis untuk input dan output di langkah sebelumnya (kode ini menggunakan semua kunci yang sama).
SaveImageToFileWorker.java
import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.work.Data;
import androidx.work.Worker;
import androidx.work.WorkerParameters;
import com.example.background.Constants;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class SaveImageToFileWorker extends Worker {
public SaveImageToFileWorker(
@NonNull Context appContext,
@NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
}
private static final String TAG = SaveImageToFileWorker.class.getSimpleName();
private static final String TITLE = "Blurred Image";
private static final SimpleDateFormat DATE_FORMATTER =
new SimpleDateFormat("yyyy.MM.dd 'at' HH:mm:ss z", Locale.getDefault());
@NonNull
@Override
public Result doWork() {
Context applicationContext = getApplicationContext();
// Makes a notification when the work starts and slows down the work so that it's easier to
// see each WorkRequest start, even on emulated devices
WorkerUtils.makeStatusNotification("Saving image", applicationContext);
WorkerUtils.sleep();
ContentResolver resolver = applicationContext.getContentResolver();
try {
String resourceUri = getInputData()
.getString(Constants.KEY_IMAGE_URI);
Bitmap bitmap = BitmapFactory.decodeStream(
resolver.openInputStream(Uri.parse(resourceUri)));
String outputUri = MediaStore.Images.Media.insertImage(
resolver, bitmap, TITLE, DATE_FORMATTER.format(new Date()));
if (TextUtils.isEmpty(outputUri)) {
Log.e(TAG, "Writing to MediaStore failed");
return Result.failure();
}
Data outputData = new Data.Builder()
.putString(Constants.KEY_IMAGE_URI, outputUri)
.build();
return Result.success(outputData);
} catch (Exception exception) {
Log.e(TAG, "Unable to save image to Gallery", exception);
return Worker.Result.failure();
}
}
}
Langkah 5 - Ubah Notifikasi BlurWorker
Sekarang setelah rantai Worker
menangani penyimpanan gambar dalam folder yang benar, kita dapat mengubah notifikasi untuk memberi tahu pengguna saat pekerjaan dimulai dan memperlambat pekerjaan sehingga lebih mudah untuk melihat setiap WorkRequest
dimulai, bahkan pada perangkat yang diemulasikan. Versi akhir BlurWorker
menjadi:
BlurWorker.java
@NonNull
@Override
public Worker.Result doWork() {
Context applicationContext = getApplicationContext();
// Makes a notification when the work starts and slows down the work so that it's easier to
// see each WorkRequest start, even on emulated devices
WorkerUtils.makeStatusNotification("Blurring image", applicationContext);
WorkerUtils.sleep();
String resourceUri = getInputData().getString(KEY_IMAGE_URI);
try {
if (TextUtils.isEmpty(resourceUri)) {
Log.e(TAG, "Invalid input uri");
throw new IllegalArgumentException("Invalid input uri");
}
ContentResolver resolver = applicationContext.getContentResolver();
// Create a bitmap
Bitmap picture = BitmapFactory.decodeStream(
resolver.openInputStream(Uri.parse(resourceUri)));
// Blur the bitmap
Bitmap output = WorkerUtils.blurBitmap(picture, applicationContext);
// Write bitmap to a temp file
Uri outputUri = WorkerUtils.writeBitmapToFile(applicationContext, output);
Data outputData = new Data.Builder()
.putString(KEY_IMAGE_URI, outputUri.toString())
.build();
// If there were no errors, return SUCCESS
return Result.success(outputData);
} catch (Throwable throwable) {
// Technically WorkManager will return Result.failure()
// but it's best to be explicit about it.
// Thus if there were errors, we're return FAILURE
Log.e(TAG, "Error applying blur", throwable);
return Result.failure();
}
}
Langkah 6 - Buat Rantai WorkRequest
Anda harus mengubah metode applyBlur
BlurViewModel
untuk mengeksekusi rantai WorkRequest
, bukan hanya satu. Saat ini, kode terlihat seperti ini:
BlurViewModel.java
void applyBlur(int blurLevel) {
OneTimeWorkRequest blurRequest =
new OneTimeWorkRequest.Builder(BlurWorker.class)
.setInputData(createInputDataForUri())
.build();
mWorkManager.enqueue(blurRequest);
}
Jangan panggil WorkManager.enqueue()
, tetapi panggil WorkManager.beginWith()
. Tindakan ini akan menampilkan WorkContinuation
, yang menentukan rantai WorkRequest
. Anda dapat menambahkan ke rantai permintaan pekerjaan ini dengan memanggil metode then()
, misalnya, jika Anda memiliki tiga objek WorkRequest
, workA
, workB
, dan workC
, Anda dapat melakukan yang berikut ini:
// Example code. Don't copy to the project
WorkContinuation continuation = mWorkManager.beginWith(workA);
continuation.then(workB) // FYI, then() returns a new WorkContinuation instance
.then(workC)
.enqueue(); // Enqueues the WorkContinuation which is a chain of work
Tindakan ini akan menghasilkan dan menjalankan rantai WorkRequest berikut:
Buat rantai CleanupWorker
WorkRequest
, BlurImage
WorkRequest
, dan SaveImageToFile
WorkRequest
di applyBlur
. Teruskan input ke BlurImage
WorkRequest
.
Kode untuk ini ada di bawah ini:
BlurViewModel.java
void applyBlur(int blurLevel) {
// Add WorkRequest to Cleanup temporary images
WorkContinuation continuation =
mWorkManager.beginWith(OneTimeWorkRequest.from(CleanupWorker.class));
// Add WorkRequest to blur the image
OneTimeWorkRequest blurRequest = new OneTimeWorkRequest.Builder(BlurWorker.class)
.setInputData(createInputDataForUri())
.build();
continuation = continuation.then(blurRequest);
// Add WorkRequest to save the image to the filesystem
OneTimeWorkRequest save =
new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
.build();
continuation = continuation.then(save);
// Actually start the work
continuation.enqueue();
}
Kode harus mengompilasi dan berjalan. Anda seharusnya dapat melihat gambar apa pun yang dipilih untuk diburamkan yang kini telah disimpan di folder Pictures:
Langkah 7 - Ulangi BlurWorker
Saatnya menambahkan kemampuan untuk memburamkan gambar dalam jumlah yang berbeda. Ambil parameter blurLevel
yang diteruskan ke applyBlur
dan tambahkan sejumlah operasi WorkRequest
pemburaman tersebut ke rantai. Hanya WorkRequest
pertama yang memerlukan dan harus mengambil input URI.
Cobalah sendiri, lalu bandingkan dengan kode di bawah ini:
BlurViewModel.java
void applyBlur(int blurLevel) {
// Add WorkRequest to Cleanup temporary images
WorkContinuation continuation = mWorkManager.beginWith(OneTimeWorkRequest.from(CleanupWorker.class));
// Add WorkRequests to blur the image the number of times requested
for (int i = 0; i < blurLevel; i++) {
OneTimeWorkRequest.Builder blurBuilder =
new OneTimeWorkRequest.Builder(BlurWorker.class);
// Input the Uri if this is the first blur operation
// After the first blur operation the input will be the output of previous
// blur operations.
if ( i == 0 ) {
blurBuilder.setInputData(createInputDataForUri());
}
continuation = continuation.then(blurBuilder.build());
}
// Add WorkRequest to save the image to the filesystem
OneTimeWorkRequest save = new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
.build();
continuation = continuation.then(save);
// Actually start the work
continuation.enqueue();
}
"Pekerjaan" yang hebat! Anda sekarang dapat memburamkan gambar sebanyak atau sesedikit yang Anda inginkan. Benar-benar misterius!
Setelah Anda menggunakan rantai, sekarang saatnya menangani fitur canggih lain dari WorkManager - rantai pekerjaan unik.
Terkadang, Anda hanya ingin menjalankan satu rantai pekerjaan dalam satu waktu. Misalnya, mungkin Anda memiliki rantai pekerjaan yang menyinkronkan data lokal dengan server - Anda mungkin ingin menyelesaikan sinkronisasi data pertama sebelum memulai yang baru. Untuk melakukannya, gunakan beginUniqueWork
, bukan beginWith
; dan berikan nama String
yang unik. Tindakan ini memberikan nama ke seluruh rantai permintaan pekerjaan sehingga Anda dapat merujuk dan mengkuerinya bersama-sama.
Pastikan rantai pekerjaan untuk memburamkan file Anda unik dengan menggunakan beginUniqueWork
. Teruskan IMAGE_MANIPULATION_WORK_NAME
sebagai kuncinya. Anda juga harus meneruskan ExistingWorkPolicy
. Opsi Anda adalah REPLACE
, KEEP
, atau APPEND
.
Anda akan menggunakan REPLACE
karena jika pengguna memutuskan untuk memburamkan gambar lain sebelum gambar saat ini selesai, kita ingin menghentikan pemburaman gambar saat ini dan mulai memburamkan gambar baru.
Kode untuk memulai kelanjutan pekerjaan unik Anda ada di bawah ini:
BlurViewModel.java
// REPLACE THIS CODE:
// WorkContinuation continuation =
// mWorkManager.beginWith(OneTimeWorkRequest.from(CleanupWorker.class));
// WITH
WorkContinuation continuation = mWorkManager
.beginUniqueWork(IMAGE_MANIPULATION_WORK_NAME,
ExistingWorkPolicy.REPLACE,
OneTimeWorkRequest.from(CleanupWorker.class));
Blur-O-Matic kini hanya akan memburamkan satu gambar dalam satu waktu.
Bagian ini akan sering menggunakan LiveData, jadi agar sepenuhnya memahami apa yang terjadi, Anda harus memahami LiveData. LiveData adalah penyimpan data yang dapat diamati dan berbasis siklus proses.
Anda dapat melihat dokumentasi atau Codelab komponen berbasis Siklus Proses Android jika ini adalah pertama kalinya Anda bekerja dengan LiveData atau observable.
Perubahan besar berikutnya yang akan Anda lakukan adalah untuk benar-benar mengubah apa yang ditampilkan di aplikasi saat Pekerjaan dieksekusi.
Anda bisa mendapatkan status WorkRequest
dengan mendapatkan LiveData
yang menyimpan objek WorkInfo
. WorkInfo
adalah objek yang berisi detail tentang status WorkRequest
saat ini, termasuk:
- Apakah pekerjaan tersebut
BLOCKED
,CANCELLED
,ENQUEUED
,FAILED
,RUNNING
, atauSUCCEEDED
- Jika
WorkRequest
selesai, semua data output dari pekerjaan.
Tabel berikut menampilkan tiga cara berbeda untuk mendapatkan objek LiveData<WorkInfo>
atau LiveData<List<WorkInfo>>
beserta fungsinya.
Jenis | Metode WorkManager | Deskripsi |
Mendapatkan pekerjaan menggunakan id |
| Setiap |
Mendapatkan pekerjaan menggunakan nama rantai unik |
| Seperti yang baru saja Anda lihat, |
Mendapatkan pekerjaan menggunakan tag |
| Terakhir, Anda dapat memberi tag pada WorkRequest mana pun dengan String. Anda dapat memberi tag beberapa |
Anda akan memberi tag SaveImageToFileWorker
WorkRequest
, agar Anda bisa mendapatkannya menggunakan getWorkInfosByTagLiveData
. Anda akan menggunakan tag untuk memberi label pekerjaan, bukan menggunakan ID WorkManager, karena jika pengguna memburamkan beberapa gambar, semua WorkRequest
gambar yang disimpan akan memiliki tag yang sama, namun bukan ID yang sama. Anda juga dapat memilih tag.
Anda tidak akan menggunakan getWorkInfosForUniqueWorkLiveData
karena akan menampilkan WorkInfo
untuk semua WorkRequest
pemburaman dan WorkRequest
pembersihan juga; serta akan membutuhkan logika tambahan untuk menemukan WorkRequest
gambar yang disimpan.
Langkah 1 - Beri tag pekerjaan Anda
Di applyBlur
, saat membuat SaveImageToFileWorker
, beri tag pekerjaan Anda menggunakan konstanta String
TAG_OUTPUT
:
BlurViewModel.java
OneTimeWorkRequest save = new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
.addTag(TAG_OUTPUT) // This adds the tag
.build();
Langkah 2 - Dapatkan WorkInfo
Setelah memberi tag pada pekerjaan, Anda bisa mendapatkan WorkInfo
:
- Deklarasikan variabel baru bernama
mSavedWorkInfo
yang merupakanLiveData<List<WorkInfo>>
- Di konstruktor
BlurViewModel
, dapatkanWorkInfo
menggunakanWorkManager.getWorkInfosByTagLiveData
- Tambahkan pengambil untuk
mSavedWorkInfo
Kode yang Anda butuhkan ada di bawah ini:
BlurViewModel.java
// New instance variable for the WorkInfo class
private LiveData<List<WorkInfo>> mSavedWorkInfo;
// Placed this code in the BlurViewModel constructor
mSavedWorkInfo = mWorkManager.getWorkInfosByTagLiveData(TAG_OUTPUT);
// Add a getter method for mSavedWorkInfo
LiveData<List<WorkInfo>> getOutputWorkInfo() { return mSavedWorkInfo; }
Langkah 3 - Tampilkan WorkInfo
Setelah memiliki LiveData
untuk WorkInfo
, Anda dapat mengamatinya di BlurActivity
. Dalam observer:
- Periksa apakah daftar
WorkInfo
bukan null dan apakah ada objekWorkInfo
di dalamnya - jika tidak ada, maka tombol Go belum diklik. Jadi, kembali. - Dapatkan
WorkInfo
pertama dalam daftar; hanya akan ada satuWorkInfo
yang diberi tag denganTAG_OUTPUT
karena kita membuat rantai pekerjaan unik. - Periksa apakah status pekerjaan telah selesai, menggunakan
workInfo.getState().isFinished();
- Jika belum selesai, panggil
showWorkInProgress()
yang menyembunyikan dan menampilkan tampilan yang sesuai. - Jika telah selesai, panggil
showWorkFinished()
yang akan menyembunyikan dan menampilkan tampilan yang sesuai.
Berikut kodenya:
BlurActivity.java
// Show work status, added in onCreate()
mViewModel.getOutputWorkInfo().observe(this, listOfWorkInfos -> {
// If there are no matching work info, do nothing
if (listOfWorkInfos == null || listOfWorkInfos.isEmpty()) {
return;
}
// We only care about the first output status.
// Every continuation has only one worker tagged TAG_OUTPUT
WorkInfo workInfo = listOfWorkInfos.get(0);
boolean finished = workInfo.getState().isFinished();
if (!finished) {
showWorkInProgress();
} else {
showWorkFinished();
}
});
Langkah 4 - Jalankan aplikasi Anda
Jalankan aplikasi Anda - aplikasi harus mengompilasi dan berjalan, dan kini menampilkan status progres saat berfungsi serta tombol batal:
Setiap WorkInfo
juga memiliki metode getOutputData
yang memungkinkan Anda untuk mendapatkan objek Data
output dengan gambar akhir yang disimpan. Mari kita tampilkan tombol See File setiap kali ada gambar buram yang siap ditampilkan.
Langkah 1 - Buat mOutputUri
Buat variabel dalam BlurViewModel
untuk URI akhir dan berikan pengambil dan penyetel untuk variabel tersebut. Untuk mengubah String
menjadi Uri
, Anda dapat menggunakan metode uriOrNull
.
Anda dapat menggunakan kode di bawah ini:
BlurViewModel.java
// New instance variable for the WorkInfo
private Uri mOutputUri;
// Add a getter and setter for mOutputUri
void setOutputUri(String outputImageUri) {
mOutputUri = uriOrNull(outputImageUri);
}
Uri getOutputUri() { return mOutputUri; }
Langkah 2 - Buat tombol See File
Sudah ada tombol di tata letak activity_blur.xml
yang tersembunyi. Tombol berada di BlurActivity
dan dapat diakses melalui View Binding-nya sebagai seeFileButton
.
Siapkan pemroses klik untuk tombol tersebut. Tombol harus mendapatkan URI, lalu membuka aktivitas untuk melihat URI tersebut. Anda dapat menggunakan kode di bawah ini:
BlurActivity.java
// Inside onCreate()
binding.seeFileButton.setOnClickListener(view -> {
Uri currentUri = mViewModel.getOutputUri();
if (currentUri != null) {
Intent actionView = new Intent(Intent.ACTION_VIEW, currentUri);
if (actionView.resolveActivity(getPackageManager()) != null) {
startActivity(actionView);
}
}
});
Langkah 3 - Tetapkan URI dan tampilkan tombol
Ada beberapa penyesuaian terakhir yang perlu Anda terapkan ke observer WorkInfo
agar pembuatan tombol berhasil:
- Jika
WorkInfo
selesai, dapatkan data output menggunakanworkInfo.getOutputData().
- Lalu dapatkan URI output, ingat bahwa URI disimpan dengan kunci
Constants.KEY_IMAGE_URI
. - Kemudian, jika tidak kosong, URI akan disimpan dengan benar; tampilkan
seeFileButton
dan panggilsetOutputUri
pada model tampilan dengan URI.
BlurActivity.java
// Replace the observer code we added in previous steps with this one.
// Show work info, goes inside onCreate()
mViewModel.getOutputWorkInfo().observe(this, listOfWorkInfo -> {
// If there are no matching work info, do nothing
if (listOfWorkInfo == null || listOfWorkInfo.isEmpty()) {
return;
}
// We only care about the first output status.
// Every continuation has only one worker tagged TAG_OUTPUT
WorkInfo workInfo = listOfWorkInfo.get(0);
boolean finished = workInfo.getState().isFinished();
if (!finished) {
showWorkInProgress();
} else {
showWorkFinished();
Data outputData = workInfo.getOutputData();
String outputImageUri = outputData.getString(Constants.KEY_IMAGE_URI);
// If there is an output file show "See File" button
if (!TextUtils.isEmpty(outputImageUri)) {
mViewModel.setOutputUri(outputImageUri);
binding.seeFileButton.setVisibility(View.VISIBLE);
}
}
});
Langkah 4 - Jalankan kode Anda
Jalankan kode. Anda akan melihat tombol See File baru yang dapat diklik, yang akan mengarahkan Anda ke file output yang dihasilkan:
Anda menambahkan tombol Cancel Work ini, jadi mari kita tambahkan kode untuk membuatnya melakukan sesuatu. Dengan WorkManager, Anda dapat membatalkan pekerjaan menggunakan ID, dengan tag dan dengan nama rantai unik.
Dalam hal ini, Anda dapat membatalkan pekerjaan dengan nama rantai unik, karena Anda ingin membatalkan semua pekerjaan dalam rantai, bukan satu langkah tertentu.
Langkah 1 - Batalkan pekerjaan dengan nama
Pada model tampilan, tulis metode untuk membatalkan pekerjaan:
BlurViewModel.java
/**
* Cancel work using the work's unique name
*/
void cancelWork() {
mWorkManager.cancelUniqueWork(IMAGE_MANIPULATION_WORK_NAME);
}
Langkah 2 - Panggil metode pembatalan
Lalu, hubungkan tombol cancelButton
untuk memanggil cancelWork
:
BlurActivity.java
// In onCreate()
// Hookup the Cancel button
binding.cancelButton.setOnClickListener(view -> mViewModel.cancelWork());
Langkah 3 - Jalankan dan batalkan pekerjaan Anda
Jalankan aplikasi Anda. Aplikasi harus mengompilasi dengan baik. Mulai buramkan gambar, lalu klik tombol batal. Seluruh rantai dibatalkan.
Terakhir, WorkManager
mendukung Constraints
. Untuk Blur-O-Matic, Anda akan menggunakan batasan sehingga perangkat harus mengisi daya saat menyimpan.
Langkah 1 - Buat dan tambahkan batasan pengisian daya
Untuk membuat objek Constraints
, gunakan Constraints.Builder
. Lalu, tetapkan batasan yang diinginkan dan tambahkan ke WorkRequest
, seperti yang ditunjukkan di bawah ini:
BlurViewModel.java
// In the applyBlur method
// Create charging constraint
Constraints constraints = new Constraints.Builder()
.setRequiresCharging(true)
.build();
// Add WorkRequest to save the image to the filesystem
OneTimeWorkRequest save = new OneTimeWorkRequest.Builder(SaveImageToFileWorker.class)
.setConstraints(constraints) // This adds the Constraints
.addTag(TAG_OUTPUT)
.build();
continuation = continuation.then(save);
Langkah 2 - Uji dengan emulator atau perangkat
Sekarang Anda dapat menjalankan Blur-O-Matic. Jika menggunakan perangkat, Anda dapat melepaskan atau mencolokkan perangkat. Pada emulator, Anda dapat mengubah status pengisian daya di jendela Extended controls:
Jika perangkat tidak mengisi daya, perangkat akan berhenti dalam status pemuatan sampai Anda mencolokkannya.
Selamat! Anda telah menyelesaikan aplikasi Blur-O-Matic dan dalam prosesnya Anda telah mempelajari:
- Menambahkan WorkManager ke Project Anda
- Menjadwalkan
OneOffWorkRequest
- Parameter Input dan Output
- Membuat rantai pekerjaan
WorkRequest
- Menamai Rantai
WorkRequest
unik - Memberi tag pada
WorkRequest
- Menampilkan
WorkInfo
di UI - Membatalkan
WorkRequest
- Menambahkan batasan ke
WorkRequest
"Kerja" bagus! Untuk melihat status akhir kode dan semua perubahan, lihat:
Atau jika mau, Anda dapat meng-clone codelab WorkManager dari GitHub:
$ git clone -b java https://github.com/googlecodelabs/android-workmanager
WorkManager mendukung banyak hal, lebih dari yang dapat kita bahas dalam codelab ini, termasuk pekerjaan berulang, support library pengujian, permintaan pekerjaan paralel, dan penggabungan input. Untuk mempelajari lebih lanjut, buka dokumentasi WorkManager.