Cara menggunakan siklus proses dan status Aktivitas

1. Selamat datang

Codelab praktis ini adalah bagian dari Unit 1: Memulai kursus Dasar-Dasar Android Developer (Versi 2). Anda akan mendapatkan manfaat maksimal dari kursus ini jika mengerjakan codelab secara berurutan:

  • Untuk mengetahui daftar lengkap codelab dalam kursus, lihat Codelabs untuk Dasar-Dasar Android Developer (V2).
  • Untuk detail tentang kursus ini, termasuk link ke semua bab, aplikasi, dan slide konsep, lihat Dasar-Dasar Android Developer (Versi 2).

Pengantar

Dalam praktik ini, Anda akan mempelajari siklus proses aktivitas lebih lanjut. Siklus proses adalah kumpulan status aktivitas selama masa aktifnya, dari saat dibuat hingga dihancurkan dan sistem mengklaim kembali resource-nya. Saat pengguna membuka beberapa aktivitas di aplikasi (serta ke dalam dan ke luar aplikasi), aktivitas akan bertransisi di antara berbagai status dalam siklus prosesnya.

Masalah IDouble

Setiap tahap dalam siklus hidup aktivitas memiliki metode callback yang sesuai: onCreate(), onStart(), onPause(), dan seterusnya. Saat sebuah aktivitas mengubah status, metode callback terkait akan dipanggil. Anda sudah melihat salah satu metode ini: onCreate(). Dengan mengganti salah satu metode callback siklus proses di class Aktivitas, Anda bisa mengubah perilaku default aktivitas sebagai respons terhadap tindakan pengguna atau sistem.

Status aktivitas juga bisa berubah sebagai respons terhadap perubahan konfigurasi perangkat, misalnya saat pengguna memutar perangkat dari orientasi potret ke lanskap. Saat perubahan konfigurasi ini terjadi, aktivitas akan dihancurkan dan dibuat ulang dalam status default, dan pengguna mungkin kehilangan informasi yang telah dimasukkan dalam aktivitas. Agar pengguna tidak bingung, Anda perlu mengembangkan aplikasi guna mencegah kehilangan data yang tidak terduga. Nanti dalam praktik ini, Anda akan bereksperimen dengan perubahan konfigurasi dan mempelajari cara mempertahankan status aktivitas sebagai respons terhadap perubahan konfigurasi perangkat dan peristiwa siklus proses aktivitas lainnya.

Dalam praktik ini Anda menambahkan laporan logging ke aplikasi TwoActivities dan mengamati perubahan siklus proses aktivitas saat menggunakan aplikasi. Selanjutnya, Anda akan mulai menangani perubahan ini dan mempelajari cara menangani input pengguna dalam kondisi ini.

Prasyarat

Anda harus sudah mampu:

  • Buat dan jalankan project aplikasi di Android Studio.
  • Tambahkan laporan log ke aplikasi Anda dan lihat log tersebut di panel Logcat.
  • Memahami dan bekerja dengan Aktivitas dan Intent, serta memahami cara berinteraksi dengannya.

Yang Akan Anda Pelajari

  • Cara kerja siklus proses Aktivitas.
  • Saat suatu Aktivitas dimulai, dijeda, dihentikan, dan dihancurkan.
  • Tentang metode callback siklus proses yang terkait dengan perubahan Aktivitas.
  • Efek tindakan (seperti perubahan konfigurasi) yang dapat menghasilkan peristiwa siklus proses Aktivitas.
  • Cara mempertahankan status Aktivitas di seluruh peristiwa siklus proses.

Yang akan Anda lakukan

  • Menambahkan kode ke aplikasi TwoActivities dari praktik sebelumnya untuk menerapkan berbagai callback siklus proses Aktivitas guna menyertakan laporan logging.
  • Mengamati perubahan status saat aplikasi berjalan dan saat Anda berinteraksi dengan setiap Aktivitas di aplikasi.
  • Memodifikasi aplikasi untuk mempertahankan status instance Aktivitas yang tanpa terduga dibuat ulang sebagai respons terhadap perilaku pengguna atau perubahan konfigurasi pada perangkat.

2. Ringkasan aplikasi

Dalam praktik ini, Anda akan menambahkan aplikasi TwoActivities. Tampilan dan perilaku aplikasi ini kurang lebih sama seperti yang ada di codelab terakhir. Aplikasi ini berisi dua implementasi Aktivitas dan memberi pengguna kemampuan untuk mengirim di antara keduanya. Perubahan yang Anda buat pada aplikasi dalam praktik ini tidak akan memengaruhi perilaku pengguna yang terlihat.

3. 3. Tugas 1. Menambahkan callback siklus proses ke TwoActivities

Dalam tugas ini Anda akan mengimplementasikan semua metode callback siklus proses Aktivitas untuk mencetak pesan ke logcat saat metode tersebut dipanggil. Pesan log ini akan memungkinkan Anda melihat kapan siklus proses Aktivitas mengubah status, dan bagaimana perubahan status siklus proses tersebut memengaruhi aplikasi Anda saat aplikasi berjalan.

1.1 (Opsional) Menyalin project TwoActivities

Untuk tugas dalam praktik ini, Anda akan memodifikasi project TwoActivities yang sudah ada, yang dibuat pada praktik sebelumnya. Jika Anda ingin mempertahankan project TwoActivities sebelumnya, ikuti langkah-langkah di Lampiran: Utilitas untuk membuat salinan project.

1.2 Mengimplementasikan callback ke MainActivity

  1. Buka project TwoActivities di Android Studio, dan buka MainActivity di panel Project > Android.
  2. Dalam metode onCreate(), tambahkan laporan log berikut:
Log.d(LOG_TAG, "-------");
Log.d(LOG_TAG, "onCreate");
  1. Tambahkan penggantian untuk callback onStart(), dengan pernyataan ke log untuk peristiwa tersebut:
@Override
public void onStart(){
    super.onStart();
    Log.d(LOG_TAG, "onStart");
}

Untuk pintasan, pilih Code > Override Methods di Android Studio. Dialog muncul dengan semua metode yang mungkin dan bisa Anda gantikan dalam kelas. Memilih satu atau beberapa metode callback dari daftar akan menyisipkan template lengkap untuk metode tersebut, termasuk panggilan wajib ke superclass.

  1. Menggunakan metode onStart() sebagai template untuk mengimplementasikan callback siklus proses onPause(), onRestart(), onResume(), onPause(), dan onDestroy()

Semua metode callback memiliki tanda tangan yang sama (kecuali untuk nama). Jika Anda menyalin dan menempel onStart() untuk membuat metode callback lain, jangan lupa untuk memperbarui kontennya agar memanggil metode yang tepat dalam superclass, dan mencatat log metode yang benar.

  1. Jalankan aplikasi Anda.
  2. Klik tab Logcat di bagian bawah Android Studio untuk menampilkan panel Logcat. Anda akan melihat tiga pesan log yang menunjukkan tiga status siklus proses yang dipindah oleh Aktivitas saat dimulai:
D/MainActivity: -------
D/MainActivity: onCreate
D/MainActivity: onStart
D/MainActivity: onResume

1.3 Mengimplementasikan callback siklus proses dalam SecondActivity

Sekarang, setelah Anda mengimplementasikan metode callback siklus proses untuk MainActivity, lakukan hal yang sama untuk SecondActivity.

  1. Buka SecondActivity.
  2. Di bagian atas class, tambahkan konstanta untuk variabel LOG_TAG:
private static final String LOG_TAG = SecondActivity.class.getSimpleName();
  1. Tambahkan callback siklus proses dan laporan log ke Aktivitas kedua. (Anda dapat Menyalin dan Tempel metode callback dari MainActivity.)
  2. Tambahkan laporan log ke metode returnReply() tepat sebelum metode finish():
Log.d(LOG_TAG, "End SecondActivity");

1.4 Mengamati log saat aplikasi berjalan**

  1. Jalankan aplikasi Anda.
  2. Klik tab Logcat di bagian bawah Android Studio untuk menampilkan panel Logcat.
  3. Masukkan Aktivitas di kotak penelusuran. Logcat Android bisa menjadi sangat panjang dan berantakan. Karena variabel LOG_TAG di setiap class berisi kata MainActivity atau SecondActivity, kata kunci ini memungkinkan Anda memfilter log hanya untuk hal-hal yang Anda minati.

Masalah IDouble

Lakukan eksperimen dengan aplikasi dan perhatikan bahwa peristiwa siklus proses terjadi sebagai respons terhadap berbagai tindakan. Khususnya, coba hal-hal berikut ini:

  • Gunakan aplikasi dengan normal (mengirim pesan, membalas dengan pesan lain).
  • Gunakan tombol Kembali untuk kembali dari Aktivitas kedua ke Aktivitas utama.
  • Gunakan Panah atas di panel aplikasi untuk kembali dari Aktivitas kedua ke Aktivitas utama.
  • Putar perangkat di Aktivitas utama dan kedua pada waktu yang berbeda di aplikasi Anda dan amati apa yang terjadi di * log dan layar.
  • Tekan tombol ringkasan (tombol kotak di sebelah kanan Layar Utama) dan tutup aplikasi (ketuk X).
  • Kembali ke layar utama dan mulai ulang aplikasi Anda.

TIPS: Jika menjalankan aplikasi di emulator, Anda dapat menyimulasikan rotasi dengan Control+F11 atau Control+Function+F11.

Kode solusi Tugas 1

Cuplikan kode berikut menunjukkan kode solusi untuk tugas pertama.

MainActivity

Cuplikan kode berikut menunjukkan kode yang ditambahkan di MainActivity, tetapi tidak seluruh class.

Metode onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Log the start of the onCreate() method.
        Log.d(LOG_TAG, "-------");
        Log.d(LOG_TAG, "onCreate");

        // Initialize all the view variables.
        mMessageEditText = findViewById(R.id.editText_main);
        mReplyHeadTextView = findViewById(R.id.text_header_reply);
        mReplyTextView = findViewById(R.id.text_message_reply);
}

Metode siklus proses lainnya:

@Override
protected void onStart() {
        super.onStart();
        Log.d(LOG_TAG, "onStart");
}

@Override
protected void onPause() {
        super.onPause();
        Log.d(LOG_TAG, "onPause");
}

@Override
protected void onRestart() {
        super.onRestart();
        Log.d(LOG_TAG, "onRestart");
}

@Override
protected void onResume() {
        super.onResume();
        Log.d(LOG_TAG, "onResume");
}

@Override
protected void onStop() {
        super.onStop();
        Log.d(LOG_TAG, "onStop");
}

@Override
protected void onDestroy() {
        super.onDestroy();
        Log.d(LOG_TAG, "onDestroy");
}

SecondActivity

Cuplikan kode berikut menampilkan kode yang ditambahkan di SecondActivity, tetapi tidak seluruh class.

Di bagian atas class SecondActivity:

private static final String LOG_TAG = SecondActivity.class.getSimpleName();

Metode returnReply():

public void returnReply(View view) {
        String reply = mReply.getText().toString();
        Intent replyIntent = new Intent();
        replyIntent.putExtra(EXTRA_REPLY, reply);
        setResult(RESULT_OK, replyIntent);
        Log.d(LOG_TAG, "End SecondActivity");
        finish();
}

Metode siklus proses lainnya:

Sama seperti MainActivity, di atas.

4. 4. Tugas 2. Menyimpan dan memulihkan status instance Aktivitas.

Bergantung pada sumber daya sistem dan perilaku pengguna, setiap Aktivitas dalam aplikasi Anda dapat dimusnahkan dan dibuat ulang jauh lebih sering dari yang Anda pikirkan.

Anda mungkin melihat perilaku ini di bagian terakhir saat memutar perangkat atau emulator. Memutar perangkat adalah salah satu contoh perubahan konfigurasi perangkat. Walaupun rotasi adalah yang paling umum, semua perubahan konfigurasi mengakibatkan Aktivitas saat ini dimusnahkan dan dibuat ulang seperti baru. Jika Anda tidak mempertimbangkan perilaku ini dalam kode, saat perubahan konfigurasi terjadi, tata letak Aktivitas mungkin akan kembali ke tampilan default dan nilai awalnya, dan pengguna Anda bisa kehilangan tempat, data, atau status kemajuannya di aplikasi Anda.

Status setiap Aktivitas disimpan sebagai serangkaian key-value pair dalam objek Bundle yang disebut status instance Aktivitas. Sistem menyimpan informasi status default ke Paket status instance tepat sebelum Aktivitas dihentikan, dan meneruskan Paket tersebut ke instance Aktivitas baru untuk dipulihkan.

Agar tidak kehilangan data dalam Aktivitas saat secara tidak terduga dihancurkan dan dibuat ulang, Anda harus mengimplementasikan metode onSaveInstanceState(). Sistem akan memanggil metode ini di Aktivitas Anda (antara onPause() dan metode Run()) jika ada kemungkinan Aktivitas akan dihancurkan dan dibuat ulang.

Data yang disimpan pada status instance hanya ditujukan untuk instance Aktivitas spesifik ini saja selama sesi aplikasi saat ini. Saat Anda menghentikan dan memulai ulang sesi aplikasi baru, status instance Aktivitas hilang dan Aktivitas kembali ke tampilan default-nya. Jika Anda perlu menyimpan data pengguna antar sesi aplikasi, gunakan database atau preferensi bersama. Anda akan mempelajari keduanya dalam praktik berikutnya.

2.1 Menyimpan status instance Aktivitas dengan onSaveInstanceState()

Anda mungkin telah memperhatikan bahwa memutar perangkat tidak memengaruhi status Aktivitas kedua sama sekali. Ini karena tata letak dan status Aktivitas kedua dihasilkan dari tata letak dan Intent yang mengaktifkannya. Meskipun Aktivitas dibuat ulang, Intent masih ada dan data dalam Intent tersebut masih digunakan setiap kali metode onCreate() di Aktivitas kedua dipanggil.

Selain itu, Anda mungkin memperhatikan bahwa di setiap Aktivitas, setiap teks yang Anda ketik ke dalam elemen EditText pesan atau balasan akan dipertahankan bahkan saat perangkat diputar. Ini karena informasi status beberapa elemen View dalam tata letak secara otomatis disimpan di semua perubahan konfigurasi, dan nilai EditText saat ini adalah salah satu contohnya.

Jadi, satu-satunya status Aktivitas yang menjadi fokus Anda adalah elemen TextView untuk header balasan dan teks balasan dalam Activity utama. Kedua elemen TextView tidak terlihat secara default, tetapi hanya muncul setelah Anda mengirim pesan kembali ke Aktivitas utama dari Aktivitas kedua.

Dalam tugas ini, Anda menambahkan kode untuk mempertahankan status instance kedua elemen TextView ini menggunakan onSaveInstanceState().

  1. Buka MainActivity.
  2. Tambahkan implementasi kerangka onSaveInstanceState() ke Aktivitas, atau gunakan Code > Override Methods untuk menyisipkan penggantian kerangka.
@Override
public void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
}
  1. Periksa untuk melihat apakah header saat ini terlihat, dan jika demikian, masukkan status visibilitas tersebut ke Paket status dengan metode putBoolean() dan kunci "reply_visible".
 if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
        outState.putBoolean("reply_visible", true);
    }

Ingat bahwa header dan teks balasan ditandai sebagai tidak terlihat sampai ada balasan dari Aktivitas kedua. Jika header terlihat, maka ada data balasan yang perlu disimpan. Perhatikan bahwa kita hanya berfokus pada status visibilitas tersebut — teks header sebenarnya tidak perlu disimpan, karena teks tersebut tidak pernah berubah.

  1. Dalam pemeriksaan yang sama, tambahkan teks balasan ke dalam Paket.
outState.putString("reply_text",mReplyTextView.getText().toString());

Jika header terlihat Anda bisa mengasumsikan bahwa pesan balasan juga terlihat. Anda tidak perlu menguji atau menyimpan status visibilitas pesan balasan saat ini. Hanya teks sebenarnya dari pesan yang masuk ke Bundle status dengan kunci "reply_text".

Anda hanya perlu menyimpan status elemen View tersebut, yang mungkin berubah setelah Aktivitas dibuat. Elemen View lainnya dalam aplikasi (EditText, Tombol) dapat dibuat ulang dari tata letak default kapan saja.

Perhatikan, sistem akan menyimpan status beberapa elemen View, seperti konten EditText.

2.2. Memulihkan status instance Aktivitas dalam onCreate()

Setelah menyimpan status instance Aktivitas, Anda juga harus memulihkannya saat Aktivitas dibuat ulang. Anda bisa melakukannya dalam onCreate(), atau dengan mengimplementasikan callback onRestoreInstanceState(), yang dipanggil setelah onStart() setelah Aktivitas dibuat.

Biasanya, tempat terbaik untuk memulihkan status Aktivitas adalah di onCreate(), untuk memastikan bahwa UI, termasuk statusnya, tersedia sesegera mungkin. Kadang lebih nyaman melakukannya dalam onRestoreInstanceState() setelah semua inisialisasi dilakukan, atau mengizinkan subclass memutuskan apakah akan menggunakan implementasi default Anda.

  1. Dalam metode onCreate(), setelah variabel Tampilan diinisialisasi dengan findViewById(), tambahkan pengujian untuk memastikan bahwaSavedInstanceState tidak null.
// Initialize all the view variables.
mMessageEditText = findViewById(R.id.editText_main);
mReplyHeadTextView = findViewById(R.id.text_header_reply);
mReplyTextView = findViewById(R.id.text_message_reply);

// Restore the state.
if (savedInstanceState != null) {
}

Saat Aktivitas Anda dibuat, sistem akan meneruskan Paket status ke onCreate() sebagai satu-satunya argumen. Pertama kali onCreate() dipanggil dan aplikasi Anda dimulai, Paket akan bernilai null—tidak ada status saat pertama kali aplikasi dimulai. Panggilan berikutnya ke onCreate() memiliki paket yang diisi dengan data yang Anda simpan di onSaveInstanceState().

  1. Di dalam pemeriksaan tersebut, dapatkan visibilitas saat ini (benar atau salah) dari Paket dengan kunci "reply_visible".
if (savedInstanceState != null) {
    boolean isVisible = 
                     savedInstanceState.getBoolean("reply_visible");
}
  1. Tambahkan pengujian di bawah baris sebelumnya untuk variabel isVisible.
if (isVisible) {
}

Jika ada kunci reply_visible dalam Bundle status (sehingga isVisible benar), Anda harus memulihkan statusnya.

  1. Di dalam pengujian isVisible, buat header-nya terlihat.
mReplyHeadTextView.setVisibility(View.VISIBLE);
  1. Dapatkan pesan balasan teks dari Paket dengan kunci "reply_text", dan setel TextView balasan untuk menampilkan string tersebut.
mReplyTextView.setText(savedInstanceState.getString("reply_text"));
  1. Buat TextView balasan juga terlihat:
mReplyTextView.setVisibility(View.VISIBLE);
  1. Jalankan aplikasi. Coba putar perangkat atau emulator untuk memastikan bahwa pesan balasan (jika ada) tetap berada di layar setelah Aktivitas dibuat ulang.

Kode solusi Tugas 2

Cuplikan kode berikut menunjukkan kode solusi untuk tugas ini.

MainActivity

Cuplikan kode berikut menunjukkan kode yang ditambahkan di MainActivity, tetapi tidak seluruh class.

Metode onSaveInstanceState():

@Override
public void onSaveInstanceState(Bundle outState) {
   super.onSaveInstanceState(outState);
   // If the heading is visible, message needs to be saved.
   // Otherwise we're still using default layout.
   if (mReplyHeadTextView.getVisibility() == View.VISIBLE) {
       outState.putBoolean("reply_visible", true);
       outState.putString("reply_text", 
                      mReplyTextView.getText().toString());
   }
}

Metode onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);

   Log.d(LOG_TAG, "-------");
   Log.d(LOG_TAG, "onCreate");

   // Initialize all the view variables.
   mMessageEditText = findViewById(R.id.editText_main);
   mReplyHeadTextView = findViewById(R.id.text_header_reply);
   mReplyTextView = findViewById(R.id.text_message_reply);

   // Restore the saved state. 
   // See onSaveInstanceState() for what gets saved.
   if (savedInstanceState != null) {
       boolean isVisible = 
                     savedInstanceState.getBoolean("reply_visible");
       // Show both the header and the message views. If isVisible is
       // false or missing from the bundle, use the default layout.
       if (isVisible) {
           mReplyHeadTextView.setVisibility(View.VISIBLE);
           mReplyTextView.setText(savedInstanceState
                                  .getString("reply_text"));
           mReplyTextView.setVisibility(View.VISIBLE);
       }
   }
}

Project yang selesai:

Project Android Studio: TwoActivitiesLifecycle

5. Coding

Tantangan: Membuat aplikasi daftar belanja sederhana dengan aktivitas utama untuk daftar yang dibuat pengguna, dan aktivitas kedua untuk daftar item belanja umum.

  • Aktivitas utama harus berisi daftar yang akan di-build, yang harus terdiri dari sepuluh elemen TextView kosong.
  • Tombol Add Item pada aktivitas utama meluncurkan aktivitas kedua yang berisi daftar item belanja umum (Keju, Rice, Apel, dan sebagainya). Menggunakan elemen Button untuk menampilkan item.
  • Memilih item akan mengembalikan pengguna ke aktivitas utama, dan memperbarui TextView kosong untuk menyertakan item yang dipilih.

Menggunakan Intent untuk meneruskan informasi dari satu Aktivitas ke Aktivitas lainnya. Pastikan status daftar belanja saat ini disimpan saat pengguna memutar perangkat.

6. Ringkasan

  • Siklus proses Aktivitas adalah kumpulan status yang dimigrasikan oleh Aktivitas, dimulai saat pertama kali dibuat dan berakhir saat sistem Android mengklaim kembali resource untuk Aktivitas tersebut.
  • Saat pengguna berpindah dari satu Aktivitas ke Aktivitas lainnya, serta di dalam dan di luar aplikasi Anda, setiap Aktivitas berpindah antar-status dalam siklus proses Aktivitas.
  • Setiap status dalam siklus proses Aktivitas memiliki metode callback yang sesuai dan dapat Anda ganti di class Aktivitas.
  • Metode siklus proses adalah onCreate(), onStart(), onPause(), onRestart(), onResume(), batas akhirnya(), onDestroy().
  • Mengganti metode callback siklus proses memungkinkan Anda menambahkan perilaku yang terjadi saat Aktivitas bertransisi ke status tersebut.
  • Anda bisa menambahkan metode pengganti kerangka ke class dalam Android Studio dengan Code > Override.
  • Perubahan konfigurasi perangkat seperti hasil rotasi dalam Aktivitas dimusnahkan dan dibuat ulang seperti baru.
  • Sebagian status Aktivitas dipertahankan pada perubahan konfigurasi, termasuk nilai elemen EditText saat ini. Untuk semua data lainnya, Anda harus secara eksplisit menyimpan data sendiri.
  • Simpan status instance Aktivitas dalam metode onSaveInstanceState().
  • Data status instance disimpan sebagai key-value pair dalam Bundle. Gunakan metode Bundle untuk memasukkan data dan mendapatkan data kembali dari Bundle.
  • Memulihkan status instance dalam onCreate(), yang merupakan cara yang direkomendasikan, atau onRestoreInstanceState(). Kembali