Dasar-Dasar Android Kotlin 04.2: Situasi siklus proses yang kompleks

Codelab ini adalah bagian dari kursus Dasar-Dasar Kotlin Android. Anda akan mendapatkan manfaat maksimal dari kursus ini jika Anda mengerjakan codelab secara berurutan. Semua codelab kursus tercantum di halaman landing codelab Dasar-Dasar Android Kotlin.

Pengantar

Dalam codelab terakhir, Anda telah mempelajari siklus proses Activity dan Fragment, dan mempelajari metode yang dipanggil saat status siklus proses berubah dalam aktivitas dan fragmen. Dalam codelab ini, Anda akan menjelajahi siklus proses aktivitas secara lebih mendetail. Anda juga mempelajari library siklus proses Android Jetpack, yang dapat membantu Anda mengelola peristiwa siklus proses dengan kode yang lebih teratur dan lebih mudah dikelola.

Yang harus sudah Anda ketahui

  • Pengertian aktivitas, dan cara membuatnya di aplikasi Anda.
  • Dasar-dasar siklus proses Activity dan Fragment, serta callback yang dipanggil saat aktivitas berpindah antar-status.
  • Cara mengganti metode callback siklus proses onCreate() dan onStop() untuk menjalankan operasi pada waktu yang berbeda di dalam siklus proses aktivitas atau fragmen.

Yang akan Anda pelajari

  • Cara menyiapkan, memulai, dan menghentikan bagian aplikasi di callback siklus proses.
  • Cara menggunakan library siklus proses Android untuk membuat observer siklus proses, dan membuat aktivitas serta siklus proses fragmen lebih mudah dikelola.
  • Cara penonaktifan proses Android memengaruhi data di aplikasi Anda, serta cara menyimpan dan memulihkan data secara otomatis saat Android menutup aplikasi.
  • Bagaimana rotasi perangkat dan perubahan konfigurasi lainnya akan membuat perubahan pada status siklus proses dan memengaruhi status aplikasi Anda.

Yang akan Anda lakukan

  • Memodifikasi aplikasi DessertClicker untuk menyertakan fungsi timer, dan memulai serta menghentikan timer tersebut pada berbagai waktu dalam siklus proses aktivitas.
  • Modifikasi aplikasi untuk menggunakan library siklus proses Android, lalu konversikan class DessertTimer menjadi pengamat siklus proses.
  • Siapkan dan gunakan Android Debug Bridge (adb) untuk menyimulasikan proses penonaktifan aplikasi dan callback siklus proses yang terjadi saat itu.
  • Menerapkan metode onSaveInstanceState() untuk mempertahankan data aplikasi yang mungkin hilang jika aplikasi ditutup secara tidak terduga. Menambahkan kode untuk memulihkan data tersebut saat aplikasi dimulai lagi.

Dalam codelab ini, Anda akan memperluas aplikasi DessertClicker dari codelab sebelumnya. Anda menambahkan timer latar belakang, lalu mengonversi aplikasi agar menggunakan library siklus proses Android.

Dalam codelab sebelumnya, Anda telah mempelajari cara mengamati siklus proses aktivitas dan fragmen dengan mengganti berbagai callback siklus proses, dan logging saat sistem memanggil callback tersebut. Dalam tugas ini, Anda akan mempelajari contoh yang lebih kompleks dalam mengelola tugas siklus proses di aplikasi DessertClicker. Anda menggunakan timer yang mencetak laporan log setiap detik, dengan hitungan jumlah detik yang telah dijalankan.

Langkah 1: Siapkan DessertTimer

  1. Buka aplikasi DessertClicker dari codelab terakhir. (Anda dapat mendownload DessertClickerLogs di sini jika tidak memiliki aplikasi tersebut.)
  2. Pada tampilan Project, luaskan j &avat; com.example.android.dessertclicker dan buka DessertTimer.kt. Perhatikan bahwa saat ini semua kode diberi komentar, sehingga tidak berjalan sebagai bagian dari aplikasi.
  3. Pilih semua kode di jendela editor. Pilih Kode > Komentar dengan Komentar Baris, atau tekan Control+/ (Command+/ di Mac). Perintah ini akan menghapus tanda komentar untuk semua kode dalam file. (Android Studio mungkin menampilkan error referensi yang belum terselesaikan hingga Anda mem-build ulang aplikasi.)
  4. Perhatikan bahwa class DessertTimer menyertakan startTimer() dan stopTimer(), yang memulai dan menghentikan timer. Saat startTimer() berjalan, timer mencetak pesan log setiap detik, dengan jumlah total detik waktu yang telah berjalan. Metode stopTimer(), pada gilirannya, menghentikan timer dan laporan log.
  1. Buka MainActivity.kt. Di bagian atas class, tepat di bawah variabel dessertsSold, tambahkan variabel untuk timer:
private lateinit var dessertTimer : DessertTimer;
  1. Scroll ke bawah ke onCreate() dan buat objek DessertTimer baru, tepat setelah panggilan ke setOnClickListener():
dessertTimer = DessertTimer()


Setelah Anda memiliki objek timer, pertimbangkan untuk memulai dan menghentikan timer agar hanya berjalan saat aktivitas ditampilkan di layar. Anda melihat beberapa opsi pada langkah berikutnya.

Langkah 2: Mulai dan hentikan timer

Metode onStart() dipanggil tepat sebelum aktivitas terlihat. Metode onStop() dipanggil setelah aktivitas berhenti terlihat. Callback ini sepertinya merupakan kandidat yang tepat untuk memulai dan menghentikan timer.

  1. Di class MainActivity, mulai timer di callback onStart():
override fun onStart() {
   super.onStart()
   dessertTimer.startTimer()

   Timber.i("onStart called")
}
  1. Hentikan timer dalam onStop():
override fun onStop() {
   super.onStop()
   dessertTimer.stopTimer()

   Timber.i("onStop Called")
}
  1. Mengompilasi dan menjalankan aplikasi. Di Android Studio, klik panel Logcat. Di kotak penelusuran Logcat, masukkan dessertclicker, yang akan difilter menurut class MainActivity dan DessertTimer. Perhatikan bahwa setelah aplikasi dimulai, timer juga segera mulai berjalan.
  2. Klik tombol Kembali dan perhatikan bahwa timer berhenti lagi. Timer berhenti karena aktivitas dan timer yang dikontrolnya telah dimusnahkan.
  3. Gunakan layar terbaru untuk kembali ke aplikasi. Perhatikan di Logcat bahwa timer dimulai ulang dari 0.
  4. Klik tombol Bagikan. Perhatikan dalam Logcat bahwa timer masih berjalan.

  5. Klik tombol Beranda. Perhatikan di Logcat bahwa timer berhenti berjalan.
  6. Gunakan layar terbaru untuk kembali ke aplikasi. Perhatikan di Logcat bahwa timer dimulai lagi dari posisi terakhir.
  7. Di MainActivity, dalam metode onStop(), jadikan komentar sebagai panggilan ke stopTimer(). Dengan mengomentari stopTimer(), Anda menunjukkan kasus saat Anda memulai operasi di onStart(), tetapi jangan lupa untuk menghentikannya lagi di onStop().
  8. Kompilasi dan jalankan aplikasi, lalu klik tombol Layar utama setelah timer dimulai. Meskipun aplikasi berada di latar belakang, timer sedang berjalan dan terus menggunakan resource sistem. Timer terus berjalan adalah kebocoran memori untuk aplikasi Anda, dan mungkin bukan perilaku yang diinginkan.

    Pola umumnya adalah saat Anda menyiapkan atau memulai sesuatu dalam callback, Anda akan menghentikan atau menghapus hal tersebut dalam callback yang sesuai. Dengan demikian, Anda tidak akan menjalankan apa pun saat tidak diperlukan lagi.
  1. Hapus tanda komentar di baris onStop() tempat Anda menghentikan timer.
  2. Potong dan tempel panggilan startTimer() dari onStart() ke onCreate(). Perubahan ini menunjukkan kasus saat Anda menginisialisasi dan memulai resource di onCreate(), bukan menggunakan onCreate() untuk menginisialisasinya dan onStart() untuk memulainya.
  3. Kompilasi dan jalankan aplikasi. Perhatikan bahwa timer mulai berjalan, seperti yang Anda harapkan.
  4. Klik Beranda untuk menghentikan aplikasi. Timer berhenti berjalan, seperti yang Anda harapkan.
  5. Gunakan layar terbaru untuk kembali ke aplikasi. Perhatikan bahwa timer tidak memulai lagi dalam kasus ini, karena onCreate() hanya dipanggil saat aplikasi dimulai—ini tidak dipanggil saat aplikasi kembali ke latar depan.

Poin penting yang perlu diingat:

  • Saat menyiapkan resource dalam callback siklus proses, Anda juga harus menghapus resource.
  • Lakukan penyiapan dan pembongkaran dengan metode yang sesuai.
  • Jika Anda menyiapkan sesuatu di onStart(), hentikan atau hancurkan lagi di onStop().

Di aplikasi DessertClicker, cukup mudah untuk melihat apakah Anda memulai timer di onStart(), maka Anda harus menghentikan timer di onStop(). Hanya ada satu timer, jadi menghentikan timer tidak sulit untuk diingat.

Di aplikasi Android yang lebih kompleks, Anda dapat menyiapkan banyak hal di onStart() atau onCreate(), lalu menghancurkan semuanya di onStop() atau onDestroy(). Misalnya, Anda mungkin memiliki animasi, musik, sensor, atau timer yang perlu disiapkan dan dihancurkan, serta memulai dan menghentikannya. Jika Anda lupa, hal itu akan menyebabkan bug dan sakit kepala.

Library siklus proses, yang merupakan bagian dari Android Jetpack, menyederhanakan tugas ini. Library sangat berguna dalam kasus saat Anda harus melacak banyak bagian yang bergerak, beberapa di antaranya berada pada status siklus proses yang berbeda. Library ini membalikkan cara kerja siklus proses: Biasanya aktivitas atau fragmen memberi tahu komponen (seperti DessertTimer) apa yang harus dilakukan saat callback siklus proses terjadi. Namun, saat Anda menggunakan library siklus proses, komponen itu sendiri akan mengamati perubahan siklus proses, lalu melakukan apa yang diperlukan saat perubahan tersebut terjadi.

Ada tiga bagian utama dari library siklus proses:

  • Pemilik siklus proses, yang merupakan komponen yang memiliki (dan dengan demikian "pemilik") siklus proses. Activity dan Fragment adalah pemilik siklus proses. Pemilik siklus proses mengimplementasikan antarmuka LifecycleOwner.
  • Class Lifecycle, yang menyimpan status pemilik siklus proses yang sebenarnya dan memicu peristiwa saat perubahan siklus proses terjadi.
  • observer siklus proses, yang mengamati status siklus proses dan melakukan tugas saat siklus proses berubah. Pengamat siklus proses mengimplementasikan antarmuka LifecycleObserver.

Dalam tugas ini, Anda mengonversi aplikasi DessertClicker untuk menggunakan library siklus proses Android, dan mempelajari bagaimana library membuat pengelolaan siklus proses fragmen dan aktivitas Android lebih mudah.

Langkah 1: Ubah DessertTimer menjadi LifecycleObserver

Bagian penting dari library siklus proses adalah konsep pengamatan siklus proses. Pengamatan memungkinkan class (seperti DessertTimer) untuk mengetahui siklus proses aktivitas atau fragmen, dan memulai serta menghentikannya sendiri sebagai respons terhadap perubahan status siklus proses tersebut. Dengan observer siklus proses, Anda dapat menghapus tanggung jawab memulai dan menghentikan objek dari metode aktivitas dan fragmen.

  1. Buka class DesertTimer.kt.
  2. Ubah tanda tangan class dari class DessertTimer agar terlihat seperti ini:
class DessertTimer(lifecycle: Lifecycle) : LifecycleObserver {

Definisi class baru ini melakukan dua hal:

  • Konstruktor mengambil objek Lifecycle, yang merupakan siklus proses yang diamati timer.
  • Definisi class mengimplementasikan antarmuka LifecycleObserver.
  1. Di bawah variabel runnable, tambahkan blok init ke definisi class. Di blok init, gunakan metode addObserver() untuk menghubungkan objek siklus proses yang diteruskan dari pemilik (aktivitas) ke class ini (pengamat).
 init {
   lifecycle.addObserver(this)
}
  1. Anotasi startTimer() dengan @OnLifecycleEvent annotation, dan gunakan peristiwa siklus proses ON_START. Semua peristiwa siklus proses yang dapat diamati oleh pengamat siklus proses Anda ada di class Lifecycle.Event.
@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun startTimer() {
  1. Lakukan hal yang sama pada stopTimer(), menggunakan peristiwa ON_STOP:
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun stopTimer()

Langkah 2: Ubah MainActivity

Class MainActivity Anda sudah menjadi pemilik siklus proses melalui pewarisan, karena superclass FragmentActivity mengimplementasikan LifecycleOwner. Oleh karena itu, tidak ada yang perlu Anda lakukan untuk membuat aktivitas Anda berbasis siklus proses. Anda hanya perlu meneruskan objek siklus proses aktivitas ke konstruktor DessertTimer.

  1. Buka MainActivity. Pada metode onCreate(), ubah inisialisasi DessertTimer untuk menyertakan this.lifecycle:
dessertTimer = DessertTimer(this.lifecycle)

Properti lifecycle aktivitas menyimpan objek Lifecycle yang dimiliki aktivitas ini.

  1. Hapus panggilan ke startTimer() di onCreate(), dan panggilan ke stopTimer() di onStop(). Anda tidak perlu memberi tahu DessertTimer apa yang harus dilakukan dalam aktivitas lagi, karena DessertTimer sekarang mengamati siklus proses itu sendiri dan otomatis diberi tahu saat status siklus proses berubah. Yang Anda lakukan di callback ini sekarang adalah mencatat pesan ke dalam log.
  2. Kompilasi dan jalankan aplikasi, lalu buka Logcat. Perhatikan bahwa timer telah mulai berjalan, seperti yang diharapkan.
  3. Klik tombol layar utama untuk menempatkan aplikasi ke latar belakang. Perhatikan bahwa timer berhenti berjalan, seperti yang diharapkan.

Apa yang terjadi pada aplikasi Anda dan datanya jika Android menghentikan aplikasi tersebut saat berada di latar belakang? Kasus ekstrem yang rumit ini perlu dipahami.

Ketika masuk ke latar belakang, aplikasi Anda tidak dihancurkan dan hanya berhenti dan menunggu pengguna kembali ke aplikasi tersebut. Tetapi salah satu masalah utama OS Android adalah membuat aktivitas yang ada di latar depan berjalan lancar. Misalnya, jika pengguna menggunakan aplikasi GPS untuk membantu mereka mengejar bus, Anda harus merender aplikasi GPS tersebut dengan cepat dan terus menampilkan rute. Penting untuk mempertahankan aplikasi DessertClicker yang mungkin tidak dilihat pengguna selama beberapa hari, yang berjalan lancar di latar belakang.

Android mengatur aplikasi latar belakang sehingga aplikasi latar depan dapat berjalan tanpa masalah. Misalnya, Android membatasi jumlah pemrosesan yang dapat dilakukan oleh aplikasi yang berjalan di latar belakang.

Terkadang Android bahkan menghentikan seluruh proses aplikasi, yang mencakup setiap aktivitas yang terkait dengan aplikasi. Android melakukan penonaktifan seperti ini saat sistem mengalami gangguan dan berisiko mengalami keterlambatan secara visual sehingga tidak ada callback atau kode tambahan yang dijalankan saat ini. Proses aplikasi Anda dihentikan di latar belakang dengan diam-diam. Namun, bagi pengguna, sepertinya aplikasi tidak ditutup. Saat pengguna membuka kembali aplikasi yang telah dinonaktifkan oleh Android OS, Android akan memulai ulang aplikasi tersebut.

Dalam tugas ini, Anda menyimulasikan penonaktifan proses Android dan memeriksa apa yang terjadi pada aplikasi saat dimulai kembali.

Langkah 1: Gunakan adb untuk menyimulasikan penghentian proses

Android Debug Bridge (adb) adalah alat command line yang memungkinkan Anda mengirim petunjuk ke emulator dan perangkat yang terpasang ke komputer Anda. Pada langkah ini, Anda menggunakan adb untuk menutup proses aplikasi dan melihat apa yang terjadi saat Android menutup aplikasi.

  1. Kompilasi dan jalankan aplikasi Anda. Klik cupcake beberapa kali.
  2. Tekan tombol Beranda untuk memindahkan aplikasi ke latar belakang. Aplikasi Anda kini dihentikan dan aplikasi akan ditutup jika Android memerlukan resource yang digunakan aplikasi.
  3. Di Android Studio, klik tab Terminal untuk membuka terminal command line.
  4. Ketik adb lalu tekan Tampilkan.

    Jika Anda melihat banyak output yang diawali dengan Android Debug Bridge version X.XX.X dan diakhiri dengan tags to be used by logcat (see logcat —help), semuanya akan baik-baik saja. Jika Anda melihat adb: command not found, pastikan perintah adb tersedia di jalur eksekusi. Untuk petunjuk, lihat "Tambahkan adb ke jalur eksekusi Anda" dalam bab Utilitas.
  5. Salin dan tempel komentar ini ke command line, lalu tekan Tampilkan:
adb shell am kill com.example.android.dessertclicker

Perintah ini memberi tahu perangkat atau emulator yang terhubung untuk menghentikan proses dengan nama paket dessertclicker, tetapi hanya jika aplikasi berada di latar belakang. Karena aplikasi Anda berada di latar belakang, tidak ada yang ditampilkan di layar emulator atau perangkat untuk menunjukkan bahwa proses telah dihentikan. Di Android Studio, klik tab Run untuk melihat pesan yang bertuliskan "Application stopped." Klik tab Logcat untuk melihat bahwa callback onDestroy() tidak pernah berjalan—aktivitas Anda baru saja berakhir.

  1. Gunakan layar terbaru untuk kembali ke aplikasi. Aplikasi Anda muncul di baru-baru ini baik saat aplikasi telah ditempatkan di latar belakang atau telah dihentikan sama sekali. Saat Anda menggunakan layar terbaru untuk kembali ke aplikasi, aktivitas akan dimulai lagi. Aktivitas ini melewati seluruh rangkaian callback siklus proses startup, termasuk onCreate().
  2. Perhatikan bahwa saat aplikasi dimulai ulang, aplikasi akan mereset "score" (jumlah makanan penutup yang terjual dan total dolar) ke nilai default (0). Jika Android mematikan aplikasi Anda, mengapa aplikasi tidak menyimpan status?

    Saat OS dimulai ulang untuk Anda, Android akan mencoba sebaik mungkin untuk mereset aplikasi ke keadaan sebelumnya. Android mengambil status beberapa tampilan Anda dan menyimpannya dalam paket setiap kali Anda keluar dari aktivitas. Beberapa contoh data yang disimpan secara otomatis adalah teks di EditText (selama ID tersebut ditetapkan di tata letak), dan data sebelumnya aktivitas Anda.

    Namun, terkadang Android OS tidak mengetahui semua data Anda. Misalnya, jika Anda memiliki variabel khusus seperti revenue di aplikasi DessertClicker, OS Android tidak mengetahui data ini atau nilai pentingnya untuk aktivitas Anda. Anda harus menambahkan data ini ke paket.

Langkah 2: Gunakan onSaveInstanceState() untuk menyimpan data paket

Metode onSaveInstanceState() adalah callback yang Anda gunakan untuk menyimpan data yang mungkin diperlukan jika OS Android memusnahkan aplikasi Anda. Dalam diagram callback siklus proses, onSaveInstanceState() akan dipanggil setelah aktivitas dihentikan. Kode tersebut akan dipanggil setiap kali aplikasi Anda masuk ke latar belakang.

Anggaplah panggilan onSaveInstanceState() sebagai tindakan keamanan; sehingga Anda dapat menyimpan sejumlah kecil informasi ke paket karena aktivitas Anda di latar depan ditutup. Sistem menyimpan data ini sekarang karena jika menunggu hingga aplikasi Anda dinonaktifkan, OS dapat berada dalam tekanan resource. Menyimpan data secara rutin akan membantu memastikan bahwa data update dalam paket dapat dipulihkan, jika diperlukan.

  1. Dalam MainActivity, ganti callback onSaveInstanceState(), dan tambahkan laporan log Timber.
override fun onSaveInstanceState(outState: Bundle) {
   super.onSaveInstanceState(outState)

   Timber.i("onSaveInstanceState Called")
}
  1. Kompilasi dan jalankan aplikasi, lalu klik tombol Beranda untuk memindahkannya ke latar belakang. Perhatikan bahwa callback onSaveInstanceState() muncul tepat setelah onPause() dan onStop():
  2. Di bagian atas file, tepat sebelum definisi class, tambahkan konstanta ini:
const val KEY_REVENUE = "revenue_key"
const val KEY_DESSERT_SOLD = "dessert_sold_key"
const val KEY_TIMER_SECONDS = "timer_seconds_key"

Anda akan menggunakan kunci ini untuk menyimpan dan mengambil data dari paket status instance.

  1. Scroll ke bawah ke onSaveInstanceState(), dan perhatikan parameter outState yang berjenis Bundle.

    Paket adalah kumpulan pasangan nilai kunci, yang kuncinya selalu berupa string. Anda dapat memasukkan nilai primitif, seperti nilai int dan boolean, ke dalam paket.
    Karena sistem menyimpan paket ini dalam RAM, praktik terbaiknya adalah menjaga data dalam paket tetap berukuran kecil. Ukuran paket ini juga terbatas, meskipun ukurannya bervariasi di setiap perangkat. Umumnya Anda harus menyimpan kurang dari 100.000. Jika tidak, aplikasi Anda berisiko mengalami error karena error TransactionTooLargeException.
  2. Dalam onSaveInstanceState(), masukkan nilai revenue (bilangan bulat) ke dalam paket dengan metode putInt():
outState.putInt(KEY_REVENUE, revenue)

Metode putInt() (dan metode serupa dari class Bundle seperti putFloat() dan putString() membutuhkan dua argumen: string untuk kunci (konstanta KEY_REVENUE) dan nilai aktual untuk disimpan.

  1. Ulangi proses yang sama dengan jumlah makanan penutup yang terjual, dan status timer:
outState.putInt(KEY_DESSERT_SOLD, dessertsSold)
outState.putInt(KEY_TIMER_SECONDS, dessertTimer.secondsCount)

Langkah 3: Gunakan onCreate() untuk memulihkan data paket

  1. Scroll sampai onCreate(), dan periksa tanda tangan metode:
override fun onCreate(savedInstanceState: Bundle) {

Perhatikan bahwa onCreate() akan mendapatkan Bundle setiap kali dipanggil. Saat aktivitas dimulai ulang karena penghentian proses, paket yang Anda simpan akan diteruskan ke onCreate(). Jika aktivitas Anda dimulai kembali dari awal, paket dalam onCreate() ini adalah null. Jadi, jika paket bukan null, Anda tahu bahwa Anda membuat ulang aktivitas dari titik yang sebelumnya telah diketahui.

  1. Tambahkan kode ini ke onCreate(), setelah penyiapan DessertTimer:
if (savedInstanceState != null) {
   revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
}

Pengujian null menentukan apakah ada data dalam paket, atau apakah paket tersebut adalah null, yang memberi tahu Anda bahwa aplikasi telah dimulai kembali dari awal atau telah dibuat ulang setelah penghentian. Pengujian ini adalah pola umum untuk memulihkan data dari paket.

Perhatikan bahwa kunci yang Anda gunakan di sini (KEY_REVENUE) adalah kunci yang sama dengan yang Anda gunakan untuk putInt(). Cara untuk memastikan Anda menggunakan kunci yang sama setiap saat adalah dengan mendefinisikan kunci tersebut sebagai konstanta. Anda menggunakan getInt() untuk mengeluarkan data dari paket, sama seperti Anda menggunakan putInt() untuk memasukkan data ke dalam paket. Metode getInt() menggunakan dua argumen:

  • String yang berfungsi sebagai kunci, misalnya "key_revenue" untuk nilai pendapatan.
  • Nilai default akan digunakan jika tidak ada nilai untuk kunci tersebut dalam paket.

Bilangan bulat yang Anda dapatkan dari paket tersebut selanjutnya akan ditetapkan ke variabel revenue, dan UI akan menggunakan nilai tersebut.

  1. Tambahkan metode getInt() untuk memulihkan jumlah makanan penutup yang terjual dan nilai timer:
if (savedInstanceState != null) {
   revenue = savedInstanceState.getInt(KEY_REVENUE, 0)dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
   dessertTimer.secondsCount =
       savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
}
  1. Kompilasi dan jalankan aplikasi. Tekan cupcake minimal lima kali hingga beralih ke donat. Klik Beranda untuk memindahkan aplikasi ke latar belakang.
  2. Di tab Terminal Android Studio, jalankan adb untuk menghentikan proses aplikasi.
adb shell am kill com.example.android.dessertclicker
  1. Gunakan layar terbaru untuk kembali ke aplikasi. Perhatikan bahwa kali ini aplikasi kembali dengan nilai pendapatan dan makanan penutup terjual yang benar dari paket. Perhatikan juga makanan penutup telah kembali ke cupcake. Ada satu hal lagi yang harus dilakukan untuk memastikan bahwa aplikasi kembali ke keadaan terakhir sebelum mati.
  2. Dalam MainActivity, periksa metode showCurrentDessert(). Perhatikan bahwa metode ini menentukan gambar makanan penutup yang akan ditampilkan dalam aktivitas berdasarkan jumlah makanan penutup yang terjual saat ini dan daftar makanan penutup di variabel allDesserts.
for (dessert in allDesserts) {
   if (dessertsSold >= dessert.startProductionAmount) {
       newDessert = dessert
   }
    else break
}

Metode ini mengandalkan jumlah makanan penutup yang terjual untuk memilih gambar yang tepat. Oleh karena itu, Anda tidak perlu melakukan apa pun untuk menyimpan referensi gambar dalam paket di onSaveInstanceState(). Dalam paket tersebut, Anda sudah menyimpan jumlah makanan penutup yang terjual.

  1. Di onCreate(), dalam blok yang memulihkan status dari paket, panggil showCurrentDessert():
 if (savedInstanceState != null) {
   revenue = savedInstanceState.getInt(KEY_REVENUE, 0)
   dessertsSold = savedInstanceState.getInt(KEY_DESSERT_SOLD, 0)
   dessertTimer.secondsCount = 
      savedInstanceState.getInt(KEY_TIMER_SECONDS, 0)
   showCurrentDessert()                   
}
  1. Kompilasi dan jalankan aplikasi, lalu letakkan di latar belakang. Gunakan adb untuk menghentikan proses. Gunakan layar terbaru untuk kembali ke aplikasi. Perlu diperhatikan bahwa nilai untuk makanan penutup yang diberitahukan, pendapatan total, dan gambar makanan penutup telah dipulihkan dengan benar.

Ada satu kasus khusus terakhir dalam mengelola siklus proses aktivitas dan fragmen yang penting untuk dipahami: bagaimana perubahan konfigurasi memengaruhi siklus proses aktivitas dan fragmen Anda.

Perubahan konfigurasi terjadi saat status perangkat berubah secara drastis sehingga cara termudah bagi sistem untuk menyelesaikan perubahan adalah dengan benar-benar menonaktifkan dan membuat ulang aktivitas. Misalnya, jika pengguna mengubah bahasa perangkat, seluruh tata letak mungkin perlu diubah untuk mengakomodasi arah teks yang berbeda. Jika pengguna mencolokkan perangkat ke dok atau menambahkan keyboard fisik, tata letak aplikasi mungkin perlu memanfaatkan ukuran tampilan atau tata letak yang berbeda. Selain itu juga, jika orientasi perangkat berubah—jika perangkat diputar dari mode potret ke mode lanskap atau kembali sebaliknya—tata letak mungkin perlu diubah agar sesuai dengan orientasi baru.

Langkah 1: Pelajari rotasi perangkat dan callback siklus proses

  1. Kompilasi dan jalankan aplikasi Anda, lalu buka Logcat.
  2. Putar perangkat atau emulator ke mode lanskap. Anda dapat memutar emulator ke kiri atau ke kanan dengan tombol rotasi, atau dengan tombol Control dan panah (Command dan tombol panah di Mac).
  3. Periksa output di Logcat. Filter output di MainActivity.
    Perhatikan bahwa saat perangkat atau emulator memutar layar, sistem akan memanggil semua callback siklus proses untuk menghentikan aktivitas. Kemudian, saat aktivitas dibuat ulang, sistem akan memanggil semua callback siklus proses untuk memulai aktivitas.
  4. Di MainActivity, jadikan komentar seluruh metode onSaveInstanceState().
  5. Kompilasi dan jalankan aplikasi Anda lagi. Klik cupcake beberapa kali, lalu putar perangkat atau emulator. Kali ini, saat perangkat diputar dan aktivitas dimatikan, lalu dibuat ulang, aktivitas dimulai dengan nilai default.

    Saat perubahan konfigurasi terjadi, Android menggunakan paket status instance yang sama dengan yang Anda pelajari di tugas sebelumnya untuk menyimpan dan memulihkan status aplikasi. Seperti halnya penonaktifan proses, gunakan onSaveInstanceState() untuk memasukkan data aplikasi Anda ke dalam paket. Kemudian, pulihkan data dalam onCreate() agar data status aktivitas tidak hilang jika perangkat diputar.
  6. Pada MainActivity, hapus tanda komentar pada metode onSaveInstanceState(), jalankan aplikasi, klik cupcake, dan putar aplikasi atau perangkat. Perhatikan saat ini data makanan penutup dipertahankan di rotasi aktivitas.

Project Android Studio: DessertClickerFinal

Tips siklus proses

  • Jika Anda menyiapkan atau memulai sesuatu dalam callback siklus proses, hentikan atau hapus hal tersebut dalam callback yang sesuai. Dengan menghentikannya, Anda memastikan hal tersebut tidak terus berjalan saat tidak diperlukan lagi. Misalnya, jika menyiapkan timer di onStart(), Anda perlu menjeda atau menghentikan timer di onStop().
  • Gunakan onCreate() hanya untuk menginisialisasi bagian aplikasi yang berjalan sekali, saat aplikasi pertama kali dimulai. Gunakan onStart() untuk memulai bagian aplikasi yang berjalan saat aplikasi dimulai, dan setiap kali aplikasi kembali ke latar depan.

Library siklus proses

  • Gunakan library siklus proses Android untuk mengalihkan kontrol siklus proses dari aktivitas atau fragmen ke komponen aktual yang perlu mengetahui siklus proses.
  • Pemilik siklus proses adalah komponen yang memiliki (dan dengan demikian "pemilik") siklus proses, termasuk Activity dan Fragment. Pemilik siklus proses mengimplementasikan antarmuka LifecycleOwner.
  • Pengamat siklus proses memperhatikan status siklus proses saat ini dan melakukan tugas saat siklus proses berubah. Pengamat siklus proses mengimplementasikan antarmuka LifecycleObserver.
  • Objek Lifecycle berisi status siklus proses yang sebenarnya, dan memicu peristiwa saat siklus proses berubah.

Untuk membuat class berbasis siklus proses:

  • Menerapkan antarmuka LifecycleObserver di class yang harus mengetahui siklus proses.
  • Lakukan inisialisasi class observer siklus proses dengan objek siklus proses dari aktivitas atau fragmen.
  • Di class observer siklus proses, beri anotasi pada metode berbasis siklus proses dengan perubahan status siklus proses yang diminatinya.

    Misalnya, anotasi @OnLifecycleEvent(Lifecycle.Event.ON_START) menunjukkan bahwa metode tersebut memantau peristiwa siklus proses onStart.

Proses penonaktifan dan menyimpan status aktivitas

  • Android mengatur aplikasi yang berjalan di latar belakang sehingga aplikasi latar depan dapat berjalan tanpa masalah. Peraturan ini mencakup pembatasan jumlah pemrosesan yang dapat dilakukan aplikasi di latar belakang, dan terkadang bahkan menghentikan seluruh proses aplikasi Anda.
  • Pengguna tidak dapat mengetahui apakah sistem telah menonaktifkan aplikasi di latar belakang. Aplikasi masih akan muncul di layar terbaru dan akan dimulai ulang dalam status yang sama dengan saat pengguna meninggalkannya.
  • Android Debug Bridge (adb) adalah alat command line yang memungkinkan Anda mengirim petunjuk ke emulator dan perangkat yang terpasang ke komputer Anda. Anda dapat menggunakan adb untuk menyimulasikan proses penonaktifan proses di aplikasi.
  • Saat Android menghentikan proses aplikasi, metode siklus proses onDestroy() tidak akan dipanggil. Aplikasi ini berhenti begitu saja.

Mempertahankan aktivitas dan status fragmen

  • Saat aplikasi Anda berpindah ke latar belakang, tepat setelah onStop() dipanggil, data aplikasi akan disimpan ke paket. Beberapa data aplikasi, seperti konten EditText, akan otomatis disimpan untuk Anda.
  • Paket tersebut adalah instance dari Bundle yang merupakan kumpulan kunci dan nilai. Kunci selalu berupa string.
  • Gunakan callback onSaveInstanceState() untuk menyimpan data lain ke paket yang ingin Anda pertahankan, meskipun aplikasi tersebut dimatikan secara otomatis. Untuk memasukkan data ke dalam paket, gunakan metode paket yang dimulai dengan put, seperti putInt().
  • Anda bisa mendapatkan kembali data dari paket dalam metode onRestoreInstanceState(), atau yang lebih umum di onCreate(). Metode onCreate() memiliki parameter savedInstanceState penyimpanan paket.
  • Jika variabel savedInstanceState berisi null, aktivitas akan dimulai tanpa paket status dan tidak ada data status yang dapat diambil.
  • Untuk mengambil data dari paket menggunakan kunci, gunakan metode Bundle yang dimulai dengan get, seperti getInt().

Perubahan konfigurasi

  • Perubahan konfigurasi terjadi saat status perangkat berubah secara drastis sehingga cara termudah bagi sistem untuk menyelesaikan perubahan adalah dengan menonaktifkan dan membuat ulang aktivitas.
  • Contoh paling umum dari perubahan konfigurasi adalah bila pengguna memutar perangkat dari mode potret ke mode lanskap, atau sebaliknya. Perubahan konfigurasi juga dapat terjadi saat bahasa perangkat berubah atau keyboard hardware dicolokkan.
  • Saat terjadi perubahan konfigurasi, Android akan memanggil semua callback penonaktifan siklus proses aktivitas. Kemudian, Android akan memulai ulang aktivitas dari awal, menjalankan semua callback startup siklus proses.
  • Saat Android menutup aplikasi karena perubahan konfigurasi, aplikasi akan memulai ulang aktivitas menggunakan paket status yang tersedia untuk onCreate().
  • Seperti halnya penonaktifan proses, simpan status aplikasi Anda ke paket di onSaveInstanceState().

Kursus Udacity:

Dokumentasi developer Android:

Lainnya:

Bagian ini mencantumkan kemungkinan tugas pekerjaan rumah untuk siswa yang mengerjakan codelab ini sebagai bagian dari kursus yang dipimpin oleh instruktur. Terserah instruktur untuk melakukan hal berikut:

  • Tugaskan pekerjaan rumah jika diperlukan.
  • Berkomunikasi dengan siswa cara mengirimkan tugas pekerjaan rumah.
  • Beri nilai tugas pekerjaan rumah.

Instruktur dapat menggunakan saran ini sesedikit atau sebanyak yang mereka inginkan, dan harus bebas memberikan pekerjaan rumah lain yang dirasa sesuai.

Jika Anda mengerjakan codelab ini sendiri, silakan gunakan tugas pekerjaan rumah ini untuk menguji pengetahuan Anda.

Mengubah aplikasi

Buka aplikasi DiceRoller dari Tutorial 1. (Anda dapat mendownload aplikasi di sini jika belum memilikinya.) Kompilasi dan jalankan aplikasi, dan perhatikan bahwa jika Anda memutar perangkat, nilai dadu saat ini akan hilang. Implementasikan onSaveInstanceState() untuk mempertahankan nilai tersebut dalam paket, dan pulihkan nilai tersebut di onCreate().

Jawab pertanyaan berikut

Pertanyaan 1

Aplikasi Anda berisi simulasi fisik yang memerlukan komputasi berat untuk ditampilkan. Kemudian, pengguna menerima panggilan telepon. Manakah di antara pilihan berikut yang benar?

  • Selama panggilan telepon, Anda harus meneruskan komputasi posisi objek pada simulasi fisik.
  • Selama panggilan telepon, Anda harus menghentikan komputasi posisi objek pada simulasi fisik.

Pertanyaan 2

Metode siklus proses mana yang harus Anda ganti untuk menjeda simulasi saat aplikasi tidak ada di layar?

  • onDestroy()
  • onStop()
  • onPause()
  • onSaveInstanceState()

Pertanyaan 3

Untuk membuat class berbasis siklus proses melalui library siklus proses Android, antarmuka mana yang harus diterapkan oleh class tersebut?

  • Lifecycle
  • LifecycleOwner
  • Lifecycle.Event
  • LifecycleObserver

Pertanyaan 4

Dalam situasi apa metode onCreate() dalam aktivitas Anda menerima Bundle dengan data di dalamnya (yaitu, Bundle bukan null)? Lebih dari satu jawaban mungkin berlaku.

  • Aktivitas dimulai ulang setelah perangkat diputar.
  • Aktivitas dimulai dari awal.
  • Aktivitas dilanjutkan setelah kembali dari latar belakang.
  • Perangkat dimulai ulang.

Mulai tutorial berikutnya: 5.1: ViewModel dan ViewModelFactory

Untuk link ke codelab lainnya dalam kursus ini, lihat halaman landing codelab Dasar-Dasar Kotlin Android.