Proses latar belakang dapat menggunakan banyak memori dan daya baterai. Misalnya, siaran implisit dapat memulai banyak proses latar belakang yang telah mendaftar untuk memantau siaran tersebut, meskipun proses itu mungkin tidak begitu berguna. Hal ini dapat berdampak besar pada performa perangkat dan pengalaman pengguna.
Untuk mengatasi masalah ini, Android 7.0 (API level 24) menerapkan pembatasan berikut:
- Aplikasi yang menargetkan Android 7.0 (API level 24) dan yang lebih tinggi tidak menerima
siaran
CONNECTIVITY_ACTION
jika aplikasi tersebut mendeklarasikan penerima siarannya di manifes. Aplikasi akan tetap menerima siaranCONNECTIVITY_ACTION
jika mendaftarkanBroadcastReceiver
denganContext.registerReceiver()
dan konteks tersebut masih valid. - Aplikasi tidak dapat mengirim atau menerima siaran
ACTION_NEW_PICTURE
atauACTION_NEW_VIDEO
. Pengoptimalan ini memengaruhi semua aplikasi, tidak hanya yang menargetkan Android 7.0 (API level 24).
Jika aplikasi Anda menggunakan salah satu intent ini, Anda harus menghapus dependensi pada intent tersebut
sesegera mungkin agar dapat menargetkan perangkat yang menjalankan Android 7.0 atau yang lebih tinggi
dengan tepat. Framework Android menyediakan beberapa solusi untuk mengurangi
kebutuhan akan siaran implisit ini. Misalnya, JobScheduler
dan
WorkManager yang baru menyediakan mekanisme andal untuk menjadwalkan operasi
jaringan jika kondisi tertentu terpenuhi, misalnya koneksi ke
jaringan tidak berbayar. Sekarang Anda juga dapat menggunakan JobScheduler
untuk merespons perubahan pada penyedia konten. Objek JobInfo
membuat enkapsulasi parameter yang digunakan JobScheduler
untuk menjadwalkan tugas Anda. Saat kondisi tugas terpenuhi, sistem
akan mengeksekusi tugas ini di JobService
aplikasi Anda.
Di halaman ini, kita akan mempelajari cara menggunakan metode alternatif, seperti
JobScheduler
, untuk menyesuaikan aplikasi Anda dengan
pembatasan baru ini.
Larangan yang diinisialisasi pengguna
Di halaman Penggunaan baterai dalam setelan sistem, pengguna dapat memilih dari opsi berikut:
- Tidak dibatasi: Mengizinkan semua pekerjaan di latar belakang, yang mungkin menggunakan lebih banyak daya baterai.
- Dioptimalkan (default): Mengoptimalkan kemampuan aplikasi untuk melakukan pekerjaan di latar belakang, berdasarkan cara pengguna berinteraksi dengan aplikasi.
- Dibatasi: Mencegah aplikasi berjalan di latar belakang sepenuhnya. Apl mungkin tidak berfungsi dengan benar.
Jika aplikasi menunjukkan beberapa perilaku buruk yang dijelaskan dalam Android vitals, sistem mungkin meminta pengguna untuk membatasi akses aplikasi tersebut ke resource sistem.
Jika sistem mendeteksi bahwa aplikasi menggunakan terlalu banyak resource, pengguna akan diberi tahu dan diberi opsi untuk membatasi tindakan aplikasi. Perilaku yang dapat memicu pemberitahuan ini meliputi:
- Penguncian layar saat aktif yang berlebihan: 1 penguncian layar saat aktif parsial ditahan selama satu jam saat layar nonaktif
- Layanan latar belakang yang berlebihan: Jika aplikasi menargetkan level API di bawah 26 dan memiliki layanan latar belakang yang berlebihan
Pembatasan pasti yang diberlakukan ditentukan oleh produsen perangkat. Misalnya, pada build AOSP yang menjalankan Android 9 (API level 28) atau yang lebih tinggi, aplikasi yang berjalan di latar belakang dalam status "dibatasi" memiliki batasan berikut:
- Tidak dapat meluncurkan layanan latar depan
- Layanan latar depan yang ada dihapus dari latar depan
- Alarm tidak terpicu
- Tugas tidak dijalankan
Selain itu, jika aplikasi menargetkan Android 13 (API level 33) atau yang lebih tinggi dan berada dalam
status "dibatasi", sistem tidak akan mengirimkan siaran BOOT_COMPLETED
atau
siaran LOCKED_BOOT_COMPLETED
hingga aplikasi dimulai untuk alasan
lain.
Pembatasan spesifik tercantum dalam Pembatasan pengelolaan daya.
Pembatasan penerimaan siaran aktivitas jaringan
Aplikasi yang menargetkan Android 7.0 (API level 24) tidak menerima siaran CONNECTIVITY_ACTION
jika sudah
mendaftar untuk menerima siaran tersebut dalam manifesnya. Semua proses yang bergantung pada
siaran ini tidak akan dimulai. Hal ini dapat menimbulkan masalah pada aplikasi yang ingin
memproses perubahan jaringan atau menjalankan aktivitas jaringan massal saat
perangkat tersambung ke jaringan tidak berbayar. Beberapa solusi untuk mengatasi pembatasan ini
sudah disediakan dalam framework Android, tetapi pemilihan solusi yang tepat
bergantung pada apa yang Anda ingin aplikasi capai.
Catatan: BroadcastReceiver
yang terdaftar pada
Context.registerReceiver()
akan terus menerima siaran ini saat aplikasi berjalan.
Menjadwalkan tugas jaringan pada koneksi tidak berbayar
Saat menggunakan class JobInfo.Builder
untuk membuat objek JobInfo
, terapkan metode setRequiredNetworkType()
dan teruskan JobInfo.NETWORK_TYPE_UNMETERED
sebagai parameter tugas. Contoh kode berikut
menjadwalkan layanan untuk berjalan saat perangkat tersambung ke
jaringan tidak berbayar dan mengisi daya:
Kotlin
const val MY_BACKGROUND_JOB = 0 ... fun scheduleJob(context: Context) { val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val job = JobInfo.Builder( MY_BACKGROUND_JOB, ComponentName(context, MyJobService::class.java) ) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build() jobScheduler.schedule(job) }
Java
public static final int MY_BACKGROUND_JOB = 0; ... public static void scheduleJob(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo job = new JobInfo.Builder( MY_BACKGROUND_JOB, new ComponentName(context, MyJobService.class)) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true) .build(); js.schedule(job); }
Saat kondisi tugas terpenuhi, aplikasi Anda akan menerima callback untuk menjalankan
metode onStartJob()
dalam
JobService.class
yang ditetapkan. Untuk melihat contoh penerapan JobScheduler
, lihat aplikasi sampel JobScheduler.
Alternatif baru untuk JobScheduler adalah WorkManager, sebuah API yang memungkinkan Anda menjadwalkan tugas latar belakang yang membutuhkan penyelesaian terjamin, terlepas dari apakah proses aplikasi tersebut aktif atau tidak. WorkManager memilih cara yang tepat untuk menjalankan tugas tersebut (baik secara langsung di thread dalam proses aplikasi Anda maupun menggunakan JobScheduler, FirebaseJobDispatcher, atau AlarmManager) berdasarkan faktor-faktor seperti API level perangkat. Selain itu, WorkManager tidak memerlukan layanan Play dan menyediakan beberapa fitur lanjutan, seperti merangkai tugas bersama-sama atau memeriksa status tugas. Untuk mempelajari lebih lanjut, lihat WorkManager.
Memantau konektivitas jaringan selagi aplikasi berjalan
Aplikasi yang sedang berjalan masih dapat memproses CONNECTIVITY_CHANGE
dengan
BroadcastReceiver
yang terdaftar. Namun, ConnectivityManager
API menyediakan metode yang lebih andal untuk meminta
callback hanya jika kondisi jaringan tertentu terpenuhi.
Objek NetworkRequest
mendefinisikan parameter
callback jaringan dari segi NetworkCapabilities
. Anda
membuat objek NetworkRequest
dengan class NetworkRequest.Builder
. Selanjutnya,
registerNetworkCallback()
meneruskan objek NetworkRequest
ke sistem. Saat
kondisi jaringan terpenuhi, aplikasi akan menerima callback untuk menjalankan
metode onAvailable()
yang ditentukan di class ConnectivityManager.NetworkCallback
.
Aplikasi akan terus menerima callback hingga aplikasi keluar atau memanggil
unregisterNetworkCallback()
.
Pembatasan penerimaan gambar dan siaran video
Di Android 7.0 (API level 24), aplikasi tidak dapat mengirim atau menerima siaran ACTION_NEW_PICTURE
atau ACTION_NEW_VIDEO
. Pembatasan ini membantu
mengurangi dampak performa dan pengalaman pengguna saat beberapa aplikasi harus
aktif untuk memproses gambar atau video baru. Android 7.0 (API level 24)
memperluas JobInfo
dan JobParameters
untuk menyediakan solusi alternatif.
Memicu tugas saat URI konten berubah
Untuk memicu tugas saat URI konten berubah, Android 7.0 (API level 24) memperluas
JobInfo
API dengan metode berikut:
-
JobInfo.TriggerContentUri()
- Melakukan enkapsulasi parameter yang diperlukan untuk memicu tugas saat URI konten berubah.
-
JobInfo.Builder.addTriggerContentUri()
-
Meneruskan objek
TriggerContentUri
keJobInfo
.ContentObserver
akan memantau URI konten yang dienkapsulasi. Jika terdapat beberapa objekTriggerContentUri
yang terkait dengan tugas, sistem akan memberikan callback meskipun perubahan yang dilaporkan hanya menyangkut salah satu URI konten. -
Tambahkan flag
TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS
untuk memicu tugas jika ada turunan dari perubahan URI yang ditentukan. Flag ini berkaitan dengan parameternotifyForDescendants
yang diteruskan keregisterContentObserver()
.
Catatan: TriggerContentUri()
tidak dapat digunakan
bersama setPeriodic()
atau setPersisted()
. Untuk terus memantau perubahan konten, jadwalkan
JobInfo
baru sebelum JobService
aplikasi selesai menangani callback terbaru.
Kode contoh berikut menjadwalkan tugas yang akan dipicu saat sistem melaporkan
perubahan pada URI konten, MEDIA_URI
:
Kotlin
const val MY_BACKGROUND_JOB = 0 ... fun scheduleJob(context: Context) { val jobScheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val job = JobInfo.Builder( MY_BACKGROUND_JOB, ComponentName(context, MediaContentJob::class.java) ) .addTriggerContentUri( JobInfo.TriggerContentUri( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS ) ) .build() jobScheduler.schedule(job) }
Java
public static final int MY_BACKGROUND_JOB = 0; ... public static void scheduleJob(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo.Builder builder = new JobInfo.Builder( MY_BACKGROUND_JOB, new ComponentName(context, MediaContentJob.class)); builder.addTriggerContentUri( new JobInfo.TriggerContentUri(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS)); js.schedule(builder.build()); }
Saat sistem melaporkan perubahan dalam URI konten yang ditentukan, aplikasi Anda
akan menerima callback dan objek JobParameters
diteruskan ke metode onStartJob()
dalam MediaContentJob.class
.
Menentukan otoritas konten yang memicu tugas
Android 7.0 (API level 24) juga memperluas JobParameters
agar
aplikasi Anda dapat menerima informasi berguna tentang URI dan otoritas konten
yang memicu tugas:
-
Uri[] getTriggeredContentUris()
-
Menampilkan array URI yang memicu tugas. Array ini akan bernilai
null
jika tidak ada URI yang memicu tugas tersebut (misalnya, tugas terpicu karena batas waktu atau alasan lain), atau jumlah URI yang berubah lebih dari 50. -
String[] getTriggeredContentAuthorities()
-
Menampilkan array string otoritas konten yang memicu tugas.
Jika array yang ditampilkan tidak bernilai
null
, gunakangetTriggeredContentUris()
untuk mengambil detail URI mana yang telah berubah.
Kode contoh berikut mengganti metode JobService.onStartJob()
dan
mencatat URI dan otoritas konten yang memicu tugas:
Kotlin
override fun onStartJob(params: JobParameters): Boolean { StringBuilder().apply { append("Media content has changed:\n") params.triggeredContentAuthorities?.also { authorities -> append("Authorities: ${authorities.joinToString(", ")}\n") append(params.triggeredContentUris?.joinToString("\n")) } ?: append("(No content)") Log.i(TAG, toString()) } return true }
Java
@Override public boolean onStartJob(JobParameters params) { StringBuilder sb = new StringBuilder(); sb.append("Media content has changed:\n"); if (params.getTriggeredContentAuthorities() != null) { sb.append("Authorities: "); boolean first = true; for (String auth : params.getTriggeredContentAuthorities()) { if (first) { first = false; } else { sb.append(", "); } sb.append(auth); } if (params.getTriggeredContentUris() != null) { for (Uri uri : params.getTriggeredContentUris()) { sb.append("\n"); sb.append(uri); } } } else { sb.append("(No content)"); } Log.i(TAG, sb.toString()); return true; }
Mengoptimalkan aplikasi Anda lebih jauh
Mengoptimalkan aplikasi agar berjalan di perangkat bermemori rendah, atau dalam kondisi memori rendah, dapat meningkatkan performa dan pengalaman pengguna. Menghapus dependensi pada layanan latar belakang dan penerima siaran implisit yang terdaftar di manifes dapat membuat aplikasi Anda berjalan lebih baik di perangkat tersebut. Meskipun Android 7.0 (API level 24) mengambil langkah untuk mengurangi sebagian masalah ini, sebaiknya Anda mengoptimalkan aplikasi agar berjalan tanpa menggunakan proses latar belakang ini sepenuhnya.
Perintah Android Debug Bridge (ADB) berikut dapat membantu Anda menguji perilaku aplikasi dengan proses latar belakang yang dinonaktifkan:
- Untuk menyimulasikan kondisi saat siaran implisit dan layanan latar belakang tidak tersedia, masukkan perintah berikut:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND ignore
- Untuk mengaktifkan kembali siaran implisit dan layanan latar belakang, masukkan perintah berikut:
-
$ adb shell cmd appops set <package_name> RUN_IN_BACKGROUND allow
- Anda dapat melakukan simulasi pengguna yang menempatkan aplikasi Anda dalam status "dibatasi" untuk penggunaan baterai di latar belakang. Setelan ini mencegah aplikasi Anda berjalan di latar belakang. Untuk melakukannya, jalankan perintah berikut di jendela terminal:
-
$ adb shell cmd appops set <PACKAGE_NAME> RUN_ANY_IN_BACKGROUND deny