Menangani perubahan konfigurasi

Beberapa konfigurasi perangkat dapat berubah saat aplikasi berjalan. Tindakan tersebut termasuk, tetapi tidak terbatas pada:

  • Ukuran tampilan aplikasi
  • Orientasi layar
  • Ketebalan dan ukuran font
  • Lokalitas
  • Mode gelap versus mode terang
  • Ketersediaan keyboard

Sebagian besar perubahan konfigurasi ini terjadi karena beberapa interaksi pengguna. Misalnya, memutar atau melipat perangkat akan mengubah jumlah ruang layar yang tersedia untuk aplikasi Anda. Demikian pula, mengubah setelan perangkat seperti ukuran font, bahasa, atau tema pilihan akan mengubah nilainya dalam objek Configuration.

Parameter ini biasanya memerlukan perubahan yang cukup besar pada UI aplikasi Anda agar platform Android memiliki mekanisme yang dibuat khusus saat berubah. Mekanisme tersebut adalah Pembuatan ulang aktivitas.

Pembuatan Ulang Aktivitas

Sistem membuat ulang Aktivitas saat terjadi perubahan konfigurasi. Sistem memanggil onDestroy() dan menghancurkan instance Aktivitas yang ada. Kemudian, instance baru akan dibuat menggunakan onCreate(). Instance Aktivitas baru ini akan melakukan inisialisasi dengan konfigurasi baru yang diupdate. Ini juga berarti bahwa sistem juga membuat ulang UI dengan konfigurasi baru.

Perilaku pembuatan ulang membantu aplikasi Anda beradaptasi dengan konfigurasi baru melalui pemuatan ulang aplikasi secara otomatis menggunakan resource alternatif yang sesuai dengan konfigurasi perangkat baru.

Contoh pembuatan ulang

Pertimbangkan TextView yang menampilkan judul statis menggunakan android:text="@string/title", seperti yang ditentukan dalam file XML tata letak. Saat dibuat, tampilan akan menyetel teks sekali saja, berdasarkan bahasa saat ini. Jika bahasa berubah, sistem akan membuat ulang aktivitas. Akibatnya, sistem juga akan membuat ulang tampilan dan melakukan inisialisasi ke nilai yang benar berdasarkan bahasa baru.

Pembuatan ulang juga menghapus status apa pun yang telah Anda simpan sebagai kolom di Aktivitas, atau dalam Fragmen, Tampilan, dan objek lain yang ada di dalamnya. Hal ini karena pembuatan ulang Aktivitas akan membuat instance Aktivitas dan UI yang benar-benar baru. Selain itu, Aktivitas lama tidak lagi terlihat atau valid, sehingga referensi lainnya ke aktivitas tersebut atau objek di dalamnya sudah usang. Hal itu dapat menyebabkan bug, kebocoran memori, dan error.

Ekspektasi pengguna

Pengguna aplikasi mengharapkan status dipertahankan. Jika pengguna mengisi formulir dan membuka aplikasi lain dalam mode multi-aplikasi untuk mereferensikan informasi, pengalaman pengguna akan menjadi buruk jika mereka kembali ke formulir yang telah dihapus, atau ke tempat yang sama sekali lain di aplikasi. Anda harus memastikan pengalaman yang konsisten melalui perubahan konfigurasi dan pembuatan ulang aktivitas.

Untuk memastikan apakah status dipertahankan di aplikasi, Anda dapat melakukan tindakan yang menyebabkan perubahan konfigurasi saat aplikasi berada di latar depan maupun di latar belakang. Tindakan ini termasuk:

  • Memutar perangkat
  • Memasuki mode multi-aplikasi
  • Mengubah ukuran aplikasi saat dalam mode multi-aplikasi atau jendela bentuk bebas
  • Melipat perangkat foldable dengan beberapa layar
  • Mengubah tema sistem, seperti mode gelap versus mode terang
  • Mengubah ukuran font
  • Mengubah bahasa sistem atau aplikasi
  • Menyambungkan atau memutuskan sambungan keyboard hardware
  • Menyambungkan atau memutuskan sambungan dok

Ada 3 pendekatan utama yang dapat Anda ambil untuk mempertahankan status yang relevan melalui pembuatan ulang aktivitas. Mana yang relevan bergantung pada jenis status yang ingin Anda pertahankan:

  • Persistensi lokal guna menangani penghentian proses untuk data yang kompleks atau besar. Penyimpanan lokal persisten mencakup database atau DataStore.
  • Objek yang dipertahankan seperti ViewModels untuk menangani status terkait UI di memori saat pengguna aktif menggunakan aplikasi.
  • Status instance tersimpan untuk menangani penghentian proses yang dimulai oleh sistem dan mempertahankan status sementara yang bergantung pada input atau navigasi pengguna.

Halaman Menyimpan status UI menjelaskan API untuk setiap status secara mendetail, dan saat yang tepat untuk menggunakan masing-masing.

Membatasi pembuatan ulang Aktivitas

Anda dapat mencegah pembuatan ulang aktivitas otomatis untuk perubahan konfigurasi tertentu. Pembuatan ulang aktivitas menyebabkan pembuatan ulang seluruh UI dan objek apa pun yang berasal dari Aktivitas. Mungkin Anda memiliki alasan bagus untuk menghindari hal tersebut. Misalnya, aplikasi Anda mungkin tidak perlu mengupdate resource selama perubahan konfigurasi tertentu, atau Anda mungkin memiliki keterbatasan performa. Dalam hal ini, Anda dapat mendeklarasikan bahwa aktivitas Anda menangani perubahan konfigurasinya sendiri dan mencegah sistem memulai ulang aktivitas.

Anda dapat menonaktifkan pembuatan ulang aktivitas untuk perubahan konfigurasi tertentu. Untuk melakukannya, tambahkan jenis konfigurasi ke android:configChanges di entri <activity> dalam AndroidManifest.xml. Nilai yang mungkin muncul dalam dokumentasi untuk atribut android:configChanges.

Kode manifes berikut menonaktifkan pembuatan ulang Aktivitas untuk MyActivity saat orientasi layar dan ketersediaan keyboard berubah:

<activity
    android:name=".MyActivity"
    android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
    android:label="@string/app_name">

Beberapa perubahan konfigurasi selalu menyebabkan aktivitas dimulai ulang. Anda tidak dapat menonaktifkannya. Misalnya, Anda tidak dapat menonaktifkan perubahan warna dinamis yang diperkenalkan di API 32. Lebih banyak perubahan konfigurasi dapat berperilaku serupa di masa mendatang.

Merespons perubahan konfigurasi dalam sistem Tampilan

Dalam sistem Tampilan, saat terjadi perubahan konfigurasi yang telah Anda nonaktifkan pembuatan ulang aktivitasnya, aktivitas akan menerima panggilan ke Activity.onConfigurationChanged(). Setiap tampilan yang dilampirkan juga akan menerima panggilan ke View.onConfigurationChanged(). Untuk perubahan konfigurasi yang belum Anda tambahkan ke android:configChanges, sistem akan membuat ulang aktivitas seperti biasa.

Metode callback onConfigurationChanged() menerima objek Configuration yang menentukan konfigurasi perangkat baru. Membaca kolom di objek Configuration untuk menentukan bagaimana seharusnya konfigurasi baru Anda. Untuk melakukan perubahan berikutnya, update resource yang Anda gunakan di antarmuka. Saat sistem memanggil metode ini, objek Resources aktivitas Anda akan diupdate untuk menampilkan resource berdasarkan konfigurasi baru. Hal ini memungkinkan Anda mereset elemen UI tanpa membuat sistem memulai ulang aktivitas Anda.

Misalnya, implementasi onConfigurationChanged() berikut memeriksa apakah keyboard tersedia:

Kotlin

override fun onConfigurationChanged(newConfig: Configuration) {
    super.onConfigurationChanged(newConfig)

    // Checks whether any keyboard is available
    if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_YES) {
        Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show()
    } else if (newConfig.keyboardHidden === Configuration.KEYBOARDHIDDEN_NO) {
        Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show()
    }
}

Java

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    // Checks whether any keyboard is available
    if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_YES) {
        Toast.makeText(this, "Keyboard available", Toast.LENGTH_SHORT).show();
    } else if (newConfig.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO){
        Toast.makeText(this, "No keyboard", Toast.LENGTH_SHORT).show();
    }
}

Jika Anda tidak perlu mengupdate aplikasi berdasarkan perubahan konfigurasi ini, Anda bisa saja tidak mengimplementasikan onConfigurationChanged(). Dalam hal ini, semua resource yang digunakan sebelum perubahan konfigurasi akan tetap digunakan dan Anda hanya menghindari mulai ulang aktivitas. Misalnya, aplikasi TV mungkin tidak ingin bereaksi saat keyboard bluetooth terpasang atau dilepas.

Mempertahankan status

Saat menggunakan teknik ini, Anda tetap harus mempertahankan status selama siklus proses aktivitas normal. Hal ini terjadi karena hal berikut:

  • Perubahan yang tidak dapat dihindari: Perubahan konfigurasi yang tidak dapat dicegah dapat memulai ulang aplikasi.
  • Penghentian proses: Aplikasi Anda harus dapat menangani penghentian proses yang dimulai oleh sistem. Jika pengguna keluar dari aplikasi dan aplikasi beralih ke latar belakang, sistem mungkin akan mengakhiri proses aplikasi tersebut.

Merespons perubahan konfigurasi di Jetpack Compose

Jetpack Compose memungkinkan aplikasi Anda bereaksi lebih mudah terhadap perubahan konfigurasi. Namun, jika menonaktifkan pembuatan ulang Aktivitas untuk semua perubahan konfigurasi yang memungkinkan, Anda tetap harus memastikan aplikasi menangani perubahan konfigurasi dengan benar.

Objek Configuration tersedia dalam hierarki UI Compose dengan lokal Komposisi LocalConfiguration. Setiap kali berubah, fungsi composable dapat membaca dari rekomposisi LocalConfiguration.current. Untuk mengetahui cara kerja lokal Komposisi, lihat dokumentasi Data yang tercakup secara lokal dengan CompositionLocal.

Contoh

Pada contoh berikut, composable menampilkan tanggal dengan format tertentu. Composable bereaksi terhadap perubahan konfigurasi lokalitas sistem dengan memanggil ConfigurationCompat.getLocales() dengan LocalConfiguration.current.

@Composable
fun DateText(year: Int, dayOfYear: Int) {
    val dateTimeFormatter = DateTimeFormatter.ofPattern(
        "MMM dd",
        ConfigurationCompat.getLocales(LocalConfiguration.current)[0]
    )
    Text(
        dateTimeFormatter.format(LocalDate.ofYearDay(year, dayOfYear))
    )
}

Untuk menghindari pembuatan ulang Aktivitas saat lokalitas berubah, Aktivitas yang menghosting kode Compose harus memilih untuk tidak mengikuti perubahan konfigurasi lokalitas. Untuk melakukannya, Anda harus menetapkan android:configChanges ke locale|layoutDirection.

Konfigurasi mengubah konsep dan ide utama

Sebagai ringkasan, berikut yang perlu Anda ketahui saat menangani perubahan konfigurasi:

  • Konfigurasi: Konfigurasi perangkat menentukan cara UI ditampilkan kepada pengguna, seperti ukuran tampilan aplikasi, lokalitas, atau tema sistem.
  • Perubahan konfigurasi: Konfigurasi berubah melalui interaksi pengguna. Misalnya, pengguna mungkin mengubah setelan perangkat atau cara mereka berinteraksi secara fisik dengan perangkat. Konfigurasi akan berubah. Tidak ada cara untuk "mencegah" perubahan konfigurasi.
  • Pembuatan ulang Aktivitas: Perubahan konfigurasi menyebabkan pembuatan ulang Aktivitas secara default. Ini adalah mekanisme bawaan untuk menginisialisasi ulang status aplikasi untuk konfigurasi baru.
  • Penghancuran Aktivitas: Pembuatan ulang aktivitas menyebabkan sistem menghancurkan instance Aktivitas lama dan membuat yang baru sebagai gantinya. Instance lama kini tidak digunakan lagi. Referensi yang tersisa akan mengakibatkan kebocoran memori, bug, atau error.
  • Status: Status dalam instance Aktivitas lama tidak ada dalam instance Aktivitas baru, karena keduanya adalah dua instance objek yang berbeda. Pertahankan aplikasi dan status pengguna seperti dijelaskan dalam Menyimpan status UI.
  • Penonaktifan: Penonaktifan pembuatan ulang aktivitas untuk jenis perubahan konfigurasi adalah kemungkinan pengoptimalan. Anda harus memastikan aplikasi Anda diupdate dengan benar sebagai reaksi terhadap konfigurasi baru.

Praktik terbaik

Untuk memberikan pengalaman pengguna yang baik, amati hal-hal berikut:

  • Perubahan konfigurasi sering terjadi: Jangan berasumsi bahwa perubahan konfigurasi jarang atau tidak pernah terjadi, terlepas dari API level, faktor bentuk, atau toolkit UI. Saat menyebabkan perubahan konfigurasi, pengguna ingin aplikasi melakukan update dan terus berfungsi dengan benar dengan konfigurasi baru.
  • Pertahankan status: Jangan sampai status pengguna hilang saat pembuatan ulang Aktivitas terjadi. Pertahankan status seperti yang dijelaskan dalam Menyimpan status UI.
  • Hindari penonaktifan sebagai perbaikan cepat: Jangan menonaktifkan pembuatan ulang Aktivitas sebagai pintasan untuk menghindari hilangnya status. Menonaktifkan pembuatan ulang aktivitas mengharuskan Anda memenuhi promise untuk menangani perubahan, dan Anda masih mungkin kehilangan status karena pembuatan ulang Aktivitas akibat perubahan konfigurasi lainnya, penghentian proses, atau penutupan aplikasi. Anda tidak dapat sepenuhnya menonaktifkan pembuatan ulang Aktivitas. Pertahankan status seperti yang dijelaskan dalam Menyimpan status UI.
  • Jangan hindari perubahan konfigurasi: Jangan terapkan pembatasan pada orientasi, rasio aspek, atau kemampuan mengubah ukuran untuk menghindari perubahan konfigurasi dan pembuatan ulang Aktivitas. Hal ini berdampak negatif terhadap pengguna yang ingin menggunakan aplikasi Anda dengan cara yang mereka inginkan.

Menangani perubahan konfigurasi berbasis ukuran

Perubahan konfigurasi berbasis ukuran dapat terjadi kapan saja. Hal ini lebih sering terjadi saat aplikasi Anda berjalan di perangkat layar besar, tempat pengguna dapat memasuki mode multi-aplikasi. Mereka menginginkan aplikasi Anda berfungsi dengan baik di lingkungan tersebut.

Ada dua jenis umum perubahan ukuran: signifikan dan tidak signifikan. Perubahan ukuran yang "signifikan" adalah perubahan dari kumpulan resource alternatif yang berbeda ke konfigurasi baru karena adanya perbedaan ukuran layar, seperti lebar, tinggi, atau lebar terkecil. Resource ini mencakup resource yang ditentukan aplikasi itu sendiri dan library apa pun yang berisi resource.

Membatasi pembuatan ulang Aktivitas untuk perubahan konfigurasi berbasis ukuran

Jika Anda menonaktifkan pembuatan ulang Aktivitas untuk perubahan konfigurasi berbasis ukuran, sistem tidak akan membuat ulang Aktivitas. Sebagai gantinya, sistem akan menerima panggilan ke Activity.onConfigurationChanged(). Setiap tampilan yang dilampirkan akan menerima panggilan ke View.onConfigurationChanged().

Mengizinkan pembuatan ulang Aktivitas untuk perubahan konfigurasi berbasis ukuran

Di API 24 dan yang lebih baru, pembuatan ulang Aktivitas hanya terjadi untuk perubahan konfigurasi berbasis ukuran jika perubahan ukuran signifikan. Jika sistem tidak membuat ulang Aktivitas karena ukuran tidak mencukupi, sistem dapat memanggil Activity.onConfigurationChanged() dan View.onConfigurationChanged() sebagai gantinya.

Ada beberapa peringatan yang harus Anda amati terkait callback Aktivitas dan Tampilan:

  • Pada API 30 dan yang lebih baru, callback Activity.onConfigurationChanged() tidak akan dipanggil.
  • Pada API 32 dan API 33, View.onConfigurationChanged() tidak akan dipanggil. Ini adalah bug yang diperbaiki dalam versi API mendatang.

Untuk kode yang bergantung pada pemrosesan perubahan konfigurasi berbasis ukuran, sebaiknya gunakan Tampilan utilitas dengan View.onConfigurationChanged() yang diganti, bukan mengandalkan pembuatan ulang Aktivitas atau Activity.onConfigurationChanged().