Bergabunglah bersama kami di ⁠#Android11: The Beta Launch Show pada tanggal 3 Juni!

Pengoptimalan tugas latar belakang

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:

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 baru 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.

Dalam dokumen ini, kita akan mempelajari cara menggunakan metode alternatif, seperti JobScheduler, untuk menyesuaikan aplikasi Anda dengan pembatasan baru ini.

Pembatasan yang dimulai pengguna

Mulai dari Android 9 (API level 28), jika aplikasi menampakkan perilaku buruk seperti yang dijelaskan dalam Android vitals, sistem akan 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:

  • Wake lock (penguncian layar saat aktif) yang berlebihan: 1 wake lock parsial ditahan selama satu jam saat layar mati
  • Layanan latar belakang yang berlebihan: Jika aplikasi menargetkan API level di bawah 26 dan memiliki layanan latar belakang yang berlebihan

Pembatasan pasti yang diberlakukan ditentukan oleh produsen perangkat. Misalnya, pada build AOSP, aplikasi yang dibatasi tidak dapat menjalankan tugas, memicu alarm, atau menggunakan jaringan, kecuali jika aplikasi tersebut berada di latar depan. (Untuk kriteria yang digunakan menentukan apakah aplikasi berada di latar depan atau tidak, lihat Batasan Layanan Latar Belakang.) 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. Solusi untuk mengatasi pembatasan ini sudah disediakan dalam framework Android, tetapi pemilihan solusi yang tepat bergantung pada apa yang Anda ingin aplikasi selesaikan.

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 level API 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 ke JobInfo. ContentObserver akan memantau URI konten yang dienkapsulasi. Jika terdapat beberapa objek TriggerContentUri 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 parameter notifyForDescendants yang diteruskan ke registerContentObserver().

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 otoritas konten dan URI 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, gunakan getTriggeredContentUris() untuk mengambil detail URI mana yang telah berubah.

Kode contoh berikut mengganti metode JobService.onStartJob() dan mencatat otoritas konten dan URI 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 nyaris kehabisan memori, dapat meningkatkan performa dan pengalaman pengguna. Menghapus dependensi pada layanan latar belakang dan penerima siaran implisit yang terdaftar di manifes dapat menjadikan 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.

Android 7.0 (API level 24) memperkenalkan beberapa perintah Android Debug Bridge (ADB) tambahan untuk menguji perilaku aplikasi dengan proses latar belakang dalam kondisi nonaktif:

  • 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