Memahami Siklus Proses Aktivitas

Saat pengguna menelusuri, keluar, dan kembali ke aplikasi Anda, instance Activity dalam aplikasi Anda melakukan transisi ke berbagai status dalam siklus prosesnya. Class Activity menyediakan sejumlah callback yang memungkinkan aktivitas mengetahui bahwa status telah berubah: bahwa sistem membuat, menghentikan, atau melanjutkan suatu aktivitas, atau menutup proses tempat beradanya aktivitas.

Dalam metode callback siklus proses, Anda dapat mendeklarasikan cara aktivitas berperilaku saat pengguna meninggalkan dan memasuki kembali aktivitas itu. Misalnya, jika sedang mem-build pemutar video streaming, Anda dapat menghentikan sementara video itu dan mengakhiri koneksi jaringan saat pengguna beralih ke aplikasi lain. Saat pengguna kembali ke aplikasi, Anda dapat menghubungkan ulang ke jaringan dan memungkinkan pengguna melanjutkan video tersebut dari titik yang sama. Dengan kata lain, setiap callback memungkinkan Anda melakukan pekerjaan tertentu yang sesuai dengan perubahan status yang diberikan. Melakukan pekerjaan yang tepat dan pada waktu yang tepat, serta menangani transisi dengan benar membuat aplikasi Anda lebih andal dan efektif. Misalnya, penerapan callback siklus proses yang baik dapat membantu memastikan Anda menghindari:

  • Error jika pengguna menerima panggilan telepon atau beralih ke aplikasi lain selagi menggunakan aplikasi Anda.
  • Penggunaan resource sistem yang berharga jika pengguna tidak secara aktif menggunakannya.
  • Kehilangan progres pengguna jika mereka keluar dari aplikasi Anda dan kembali lagi nanti.
  • Error atau kehilangan progres pengguna ketika layar berputar antara orientasi lanskap dan potret.

Dokumen ini menjelaskan siklus proses aktivitas secara detail. Dokumen dimulai dengan menjelaskan paradigma siklus proses. Selanjutnya, dokumen menjelaskan masing-masing callback: apa yang terjadi secara internal saat callback mengeksekusi, dan apa yang harus Anda terapkan selama itu. Selanjutnya, dokumen tersebut secara singkat memperkenalkan hubungan antara status aktivitas dan kerentanan suatu proses akan ditutup oleh sistem. Terakhir, dokumen ini membahas beberapa topik yang terkait dengan transisi antara status aktivitas.

Untuk informasi tentang penanganan siklus proses, termasuk panduan terkait praktik terbaik, lihat Menangani Siklus Proses dengan Komponen Berbasis Siklus Proses dan Menyimpan Status UI. Untuk mempelajari cara merancang aplikasi yang andal dan berkualitas produksi menggunakan aktivitas yang dikombinasikan dengan komponen arsitektur, lihat Panduan untuk Arsitektur Aplikasi.

Konsep siklus proses aktivitas

Untuk menavigasi transisi di antara tahap siklus proses aktivitas, class Activity menyediakan set inti sebanyak enam callback: onCreate(), onStart(), onResume(), onPause(), onStop(), dan onDestroy(). Sistem memanggil masing-masing callback ini saat aktivitas memasuki status baru.

Gambar 1 menyajikan representasi visual dari paradigma ini.

Gambar 1. Ilustrasi sederhana dari siklus proses aktivitas.

Setelah pengguna mulai meninggalkan aktivitas, sistem memanggil metode untuk membongkar aktivitas. Biasanya, pembongkaran ini hanya sebagian; aktivitas masih berada dalam memori (seperti ketika pengguna beralih ke aplikasi lain), dan masih dapat kembali ke latar depan. Jika pengguna kembali ke aktivitas itu, aktivitas akan dilanjutkan dari tempat pengguna keluar. Dengan beberapa pengecualian, aplikasi dibatasi dari memulai aktivitas saat berjalan di latar belakang.

Kemungkinan sistem untuk menutup proses yang diberikan—bersama dengan aktivitas di dalamnya—tergantung pada status aktivitas pada saat itu. Status aktivitas dan pengeluaran dari memori memberikan informasi selengkapnya tentang hubungan antara status dan kerentanan terhadap pengeluaran.

Bergantung pada kompleksitas aktivitas, Anda mungkin tidak perlu mengimplementasikan semua metode siklus proses. Akan tetapi, Anda perlu memahami masing-masing metode dan mengimplementasikan metode tersebut untuk memastikan aplikasi berperilaku seperti harapan pengguna.

Bagian selanjutnya dari dokumen ini memberikan detail tentang callback yang Anda gunakan untuk menangani transisi antar-status.

Callback siklus proses

Bagian ini memberikan informasi konseptual dan implementasi tentang metode callback yang digunakan selama siklus proses aktivitas.

Beberapa tindakan, seperti memanggil setContentView(), termasuk dalam metode siklus proses aktivitas itu sendiri. Namun, kode yang menerapkan tindakan komponen dependen harus ditempatkan dalam komponen itu sendiri. Untuk mencapai ini, Anda harus membuat komponen dependen berbasis siklus proses. Lihat Menangani Siklus Proses dengan Komponen Berbasis Siklus Proses untuk mempelajari cara membuat komponen dependen berbasis siklus proses.

onCreate()

Anda harus menerapkan callback ini, yang aktif saat sistem pertama kali membuat aktivitas. Pada pembuatan aktivitas, aktivitas memasuki status Dibuat. Dalam metode onCreate(), Anda menjalankan logika startup aplikasi dasar yang hanya boleh terjadi sekali selama siklus aktivitas. Misalnya, implementasi onCreate() mungkin mengikat data ke daftar, mengaitkan aktivitas dengan ViewModel, dan membuat instance beberapa variabel lingkup class. Metode ini menerima parameter savedInstanceState, yang merupakan objek Bundle yang berisi status aktivitas yang sebelumnya disimpan. Jika aktivitas belum pernah ada sebelumnya, nilai objek Bundle adalah nol.

Jika Anda memiliki komponen berbasis siklus proses yang terhubung dengan siklus proses aktivitas Anda, aktivitas akan menerima peristiwa ON_CREATE. Metode yang dijelaskan dengan @OnLifecycleEvent akan dipanggil sehingga komponen berbasis siklus proses Anda dapat melakukan kode penyiapan apa pun yang diperlukan untuk status yang dibuat.

Contoh berikut dari metode onCreate() menunjukkan penyiapan dasar untuk aktivitas, seperti mendeklarasikan antarmuka pengguna (didefinisikan dalam file tata letak XML), mendefinisikan variabel anggota, dan mengonfigurasi beberapa UI. Dalam contoh ini, file tata letak XML ditentukan dengan mengirimkan ID resource file R.layout.main_activity ke setContentView().

Kotlin

lateinit var textView: TextView

// some transient state for the activity instance
var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // call the super class onCreate to complete the creation of activity like
    // the view hierarchy
    super.onCreate(savedInstanceState)

    // recovering the instance state
    gameState = savedInstanceState?.getString(GAME_STATE_KEY)

    // set the user interface layout for this activity
    // the layout file is defined in the project res/layout/main_activity.xml file
    setContentView(R.layout.main_activity)

    // initialize member TextView so we can manipulate it later
    textView = findViewById(R.id.text_view)
}

// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}

// invoked when the activity may be temporarily destroyed, save the instance state here
override fun onSaveInstanceState(outState: Bundle?) {
    outState?.run {
        putString(GAME_STATE_KEY, gameState)
        putString(TEXT_VIEW_KEY, textView.text.toString())
    }
    // call superclass to save any view hierarchy
    super.onSaveInstanceState(outState)
}

Java

TextView textView;

// some transient state for the activity instance
String gameState;

@Override
public void onCreate(Bundle savedInstanceState) {
    // call the super class onCreate to complete the creation of activity like
    // the view hierarchy
    super.onCreate(savedInstanceState);

    // recovering the instance state
    if (savedInstanceState != null) {
        gameState = savedInstanceState.getString(GAME_STATE_KEY);
    }

    // set the user interface layout for this activity
    // the layout file is defined in the project res/layout/main_activity.xml file
    setContentView(R.layout.main_activity);

    // initialize member TextView so we can manipulate it later
    textView = (TextView) findViewById(R.id.text_view);
}

// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}

// invoked when the activity may be temporarily destroyed, save the instance state here
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, gameState);
    outState.putString(TEXT_VIEW_KEY, textView.getText());

    // call superclass to save any view hierarchy
    super.onSaveInstanceState(outState);
}

Sebagai alternatif untuk mendefinisikan file XML dan meneruskannya ke setContentView(), Anda dapat membuat objek View baru dalam kode aktivitas Anda dan mem-build hierarki tampilan dengan memasukkan View baru ke ViewGroup. Anda kemudian menggunakan tata letak tersebut dengan meneruskan root ViewGroup ke setContentView(). Untuk informasi selengkapnya tentang membuat antarmuka pengguna, lihat dokumentasi Antarmuka Pengguna.

Aktivitas Anda tidak berada pada status Dibuat. Setelah metode onCreate() menyelesaikan eksekusi, aktivitas memasuki status Dimulai, dan sistem memanggil metode onStart() dan onResume() dalam urutan cepat. Bagian selanjutnya menjelaskan callback onStart().

onStart()

Ketika aktivitas memasuki status Dimulai, sistem memanggil callback ini. Panggilan onStart() membuat aktivitas terlihat oleh pengguna, saat aplikasi mempersiapkan aktivitas untuk memasuki latar depan dan menjadi interaktif. Misalnya, metode ini adalah tempat aplikasi menginisialisasi kode yang mengelola UI.

Saat aktivitas berpindah ke status dimulai, komponen berbasis siklus proses apa pun yang terkait dengan siklus proses aktivitas akan menerima peristiwa ON_START.

Metode onStart() selesai dengan sangat cepat dan, seperti pada status Dibuat, aktivitas tidak tetap berada dalam status Dimulai. Setelah callback ini selesai, aktivitas memasuki status Dilanjutkan, dan sistem memanggil metode onResume().

onResume()

Setelah aktivitas memasuki status Dilanjutkan, aktivitas tersebut masuk ke latar depan, kemudian sistem memanggil callback onResume(). Ini adalah status saat aplikasi berinteraksi dengan pengguna. Aplikasi tetap dalam status ini sampai terjadi sesuatu untuk mengambil fokus dari aplikasi. Peristiwa yang terjadi misalnya adalah menerima panggilan telepon, pengguna beralih ke aktivitas lain, atau layar perangkat mati.

Saat aktivitas berpindah ke status dilanjutkan, komponen berbasis siklus proses apa pun yang terkait dengan siklus proses aktivitas akan menerima peristiwa ON_RESUME. Di sinilah komponen siklus proses dapat mengaktifkan fungsi apa pun yang perlu dijalankan saat komponen terlihat dan berada di latar depan, seperti memulai pratinjau kamera.

Jika terjadi suatu peristiwa interupsi, aktivitas memasuki status Dijeda, dan sistem memanggil callback onPause().

Jika aktivitas kembali ke status Dilanjutkan dari status Dijeda, sistem akan memanggil metode onResume() sekali lagi. Untuk alasan ini, Anda harus menerapkan onResume() untuk menginisialisasi komponen yang Anda rilis selama onPause(), dan melakukan inisialisasi lainnya yang harus terjadi setiap kali aktivitas memasuki status Dilanjutkan.

Berikut adalah contoh komponen berbasis siklus proses yang mengakses kamera ketika komponen menerima peristiwa ON_RESUME:

Kotlin

class CameraComponent : LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }

    ...
}

Java

public class CameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void initializeCamera() {
        if (camera == null) {
            getCamera();
        }
    }

    ...
}

Kode di atas menginisialisasi kamera setelah LifecycleObserver menerima peristiwa ON_RESUME. Namun, dalam mode multi-jendela, aktivitas Anda mungkin sepenuhnya terlihat meski sedang dalam status Dijeda. Misalnya, ketika pengguna berada dalam mode multi-jendela dan mengetuk jendela lain yang tidak berisi aktivitas Anda, aktivitas Anda akan pindah ke status Dijeda. Jika Anda ingin kamera hanya aktif saat aplikasi Dilanjutkan (terlihat dan aktif di latar depan), lakukan inisialisasi kamera setelah peristiwa ON_RESUME yang ditunjukkan di atas. Jika ingin kamera tetap aktif saat aktivitas Dijeda tetapi terlihat (mis. dalam mode multi-jendela), Anda harus menginisialisasi kamera setelah peristiwa ON_START. Namun, perlu diketahui bahwa mengaktifkan kamera saat aktivitas Dijeda dapat menolak akses ke kamera untuk aplikasi yang Dilanjutkan dalam mode multi-jendela. Kadang-kadang hal tersebut mungkin diperlukan untuk menjaga kamera tetap aktif saat aktivitas Dijeda, tetapi sebenarnya hal ini dapat menurunkan pengalaman pengguna secara keseluruhan. Pikirkan baik-baik jika dalam siklus proses, lebih tepat untuk mengendalikan resource sistem bersama dalam konteks multi-jendela. Untuk mempelajari dukungan mode multi-jendela lebih lanjut, baca Dukungan Multi-Jendela.

Terlepas dari peristiwa build-up yang Anda pilih untuk melakukan operasi inisialisasi, pastikan untuk menggunakan peristiwa siklus proses yang sesuai untuk melepaskan resource. Jika Anda menginisialisasi sesuatu setelah peristiwa ON_START, lepaskan atau hentikan setelah peristiwa ON_STOP. Jika Anda menginisialisasi setelah peristiwa ON_RESUME, rilis setelah peristiwa ON_PAUSE.

Perlu dicatat bahwa cuplikan kode di atas menempatkan kode inisialisasi kamera dalam komponen berbasis siklus proses. Anda dapat memasukkan kode ini langsung ke callback siklus proses aktivitas seperti onStart() dan onStop(), tetapi ini tidak direkomendasikan. Menambahkan logika ini ke dalam komponen yang mandiri dan berbasis siklus proses memungkinkan Anda menggunakan kembali komponen tersebut di berbagai aktivitas tanpa harus menduplikasi kode. Lihat Menangani Siklus Proses dengan Komponen Berbasis Siklus Proses untuk mempelajari cara membuat komponen berbasis siklus proses.

onPause()

Sistem akan memanggil metode ini sebagai indikasi pertama bahwa pengguna meninggalkan aktivitas Anda (meskipun tidak selalu berarti aktivitas sedang ditutup); hal ini menunjukkan bahwa aktivitas tidak lagi di latar depan (meskipun mungkin masih terlihat jika pengguna berada dalam mode multi-jendela). Gunakan metode onPause() untuk menjeda atau menyesuaikan operasi yang tidak boleh dilanjutkan (atau harus dilanjutkan dalam jumlah sedang) sementara Activity berada dalam status Dijeda, dan Anda berharap untuk segera melanjutkan. Ada beberapa alasan mengapa suatu aktivitas dapat memasuki status ini. Contoh:

  • Beberapa acara mengganggu eksekusi aplikasi, seperti yang dijelaskan pada bagian onResume(). Ini adalah kasus yang paling umum.
  • Di Android 7.0 (API level 24) atau lebih tinggi, beberapa aplikasi berjalan dalam mode multi-jendela. Karena hanya satu aplikasi (jendela) yang memiliki fokus di setiap waktu, sistem menjeda semua aplikasi lain.
  • Aktivitas semi-transparan baru (seperti dialog) terbuka. Selama aktivitas masih terlihat sebagian tetapi tidak dalam fokus, aktivitas tersebut tetap dijeda.

Saat aktivitas berpindah ke status dijeda, komponen berbasis siklus proses yang terkait dengan siklus proses aktivitas akan menerima peristiwa ON_PAUSE. Di sinilah komponen siklus proses dapat menghentikan fungsi apa pun yang tidak perlu dijalankan saat komponen tidak ada di latar depan, seperti menghentikan pratinjau kamera.

Anda juga dapat menggunakan metode onPause() untuk melepaskan resource sistem, menangani sensor (seperti GPS), atau resource apa pun yang dapat memengaruhi masa pakai baterai saat aktivitas Anda dijeda dan pengguna tidak membutuhkannya. Namun, seperti yang disebutkan di atas di bagian onResume(), aktivitas yang Dijeda mungkin masih sepenuhnya terlihat jika berada dalam mode multi-jendela. Karena itu, Anda harus mempertimbangkan menggunakan onStop() daripada onPause() untuk sepenuhnya melepaskan atau menyesuaikan resource dan operasi terkait UI untuk lebih optimal mendukung mode multi-jendela.

Contoh LifecycleObserver berikut yang menanggapi peristiwa ON_PAUSE adalah kebalikan dari contoh peristiwa ON_RESUME di atas, dengan merilis kamera yang diinisialisasi setelah peristiwa ON_RESUME diterima:

Kotlin

class CameraComponent : LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }

    ...
}

Java

public class JavaCameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }

    ...
}

Perlu dicatat bahwa cuplikan kode di atas menempatkan kode rilis kamera setelah peristiwa ON_PAUSE diterima oleh LifecycleObserver. Seperti disebutkan sebelumnya, baca Menangani Siklus Proses dengan Komponen Berbasis Siklus Proses untuk mempelajari cara membuat komponen berbasis siklus proses.

Eksekusi onPause() sangat singkat, dan tidak perlu banyak waktu untuk melakukan operasi penyimpanan. Karena alasan ini, Anda tidak boleh menggunakan onPause() untuk menyimpan data aplikasi atau pengguna, melakukan panggilan jaringan, atau melakukan transaksi database; pekerjaan seperti itu mungkin tidak akan selesai sebelum metode selesai. Sebagai gantinya, Anda harus melakukan operasi penonaktifan yang berat selama onStop(). Untuk informasi tentang operasi yang sesuai yang harus dilakukan selama onStop() selengkapnya, lihat onStop(). Untuk informasi tentang menyimpan data selengkapnya, baca Menyimpan dan memulihkan status aktivitas.

Penyelesaian metode onPause() tidak berarti bahwa aktivitas meninggalkan status Dijeda. Sebaliknya, aktivitas tetap dalam status ini sampai aktivitas dilanjutkan atau menjadi tidak terlihat sama sekali oleh pengguna. Jika aktivitas berlanjut, sistem sekali lagi memanggil callback onResume(). Jika aktivitas kembali dari status Dijeda ke status Dilanjutkan, sistem akan menyimpan instance Activity tetap ada di memori, dan memanggil kembali instance tersebut ketika sistem memanggil onResume(). Dalam skenario ini, Anda tidak perlu menginisialisasi ulang komponen yang dibuat selama salah satu metode callback mengarah ke status Dilanjutkan. Jika aktivitas menjadi benar-benar tidak terlihat, sistem akan memanggil onStop(). Bagian berikutnya membahas callback onStop().

onStop()

Jika aktivitas Anda tidak lagi terlihat oleh pengguna, aktivitas tersebut telah memasuki status Berhenti, dan sistem memanggil callback onStop(). Ini dapat terjadi, misalnya, ketika aktivitas yang baru diluncurkan menutupi seluruh layar. Sistem juga dapat memanggil onStop() ketika aktivitas telah selesai berjalan, dan akan segera dihentikan.

Saat aktivitas beralih ke status berhenti, komponen berbasis siklus proses yang terkait dengan siklus proses aktivitas akan menerima peristiwa ON_STOP. Di sinilah komponen siklus proses dapat menghentikan fungsi apa pun yang tidak perlu dijalankan saat komponen tidak terlihat di layar.

Dalam metode onStop(), aplikasi harus melepaskan atau menyesuaikan resource yang tidak diperlukan saat aplikasi tidak terlihat oleh pengguna. Misalnya, aplikasi Anda dapat menjeda animasi atau beralih dari pembaruan lokasi yang sangat akurat ke kurang akurat. Menggunakan onStop(), dan bukannya onPause() akan memastikan bahwa pekerjaan terkait UI berlanjut, meski pengguna melihat aktivitas Anda dalam mode multi-jendela.

Anda juga harus menggunakan onStop() untuk melakukan operasi penghentian yang relatif intensif CPU. Misalnya, jika Anda tidak dapat menemukan waktu yang lebih tepat untuk menyimpan informasi ke database, Anda dapat melakukannya selama onStop(). Contoh berikut menunjukkan implementasi onStop() yang menyimpan konten catatan draf ke penyimpanan persisten:

Kotlin

override fun onStop() {
    // call the superclass method first
    super.onStop()

    // save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    val values = ContentValues().apply {
        put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
        put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
    }

    // do this update in background on an AsyncQueryHandler or equivalent
    asyncQueryHandler.startUpdate(
            token,     // int token to correlate calls
            null,      // cookie, not used here
            uri,       // The URI for the note to update.
            values,    // The map of column names and new values to apply to them.
            null,      // No SELECT criteria are used.
            null       // No WHERE columns are used.
    )
}

Java

@Override
protected void onStop() {
    // call the superclass method first
    super.onStop();

    // save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    // do this update in background on an AsyncQueryHandler or equivalent
    asyncQueryHandler.startUpdate (
            mToken,  // int token to correlate calls
            null,    // cookie, not used here
            uri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
    );
}

Perlu dicatat bahwa contoh kode di atas menggunakan SQLite secara langsung. Anda sebaiknya menggunakan Room, library persistensi yang menyediakan lapisan abstraksi atas SQLite. Untuk mempelajari lebih lanjut manfaat menggunakan Room, dan cara menerapkan Room di aplikasi Anda, baca panduan Library Persistensi Room.

Saat aktivitas Anda memasuki status Berhenti, objek Activity disimpan di memori: Ini akan mempertahankan semua informasi status dan anggota, tetapi tidak dilampirkan ke pengelola jendela. Ketika dilanjutkan, aktivitas akan mengingat kembali informasi ini. Anda tidak perlu melakukan inisialisasi ulang komponen yang dibuat selama metode callback yang mengarah ke status Dilanjutkan. Sistem juga melacak status saat ini untuk setiap objek View dalam tata letak, jadi jika pengguna memasukkan teks ke dalam widget EditText, konten tersebut dipertahankan sehingga Anda tidak perlu menyimpan dan memulihkannya.

Catatan: Setelah aktivitas Anda dihentikan, sistem mungkin menghancurkan proses yang berisi aktivitas jika sistem perlu memulihkan memori. Meskipun sistem menutup proses ketika aktivitas dihentikan, sistem masih mempertahankan status objek View (seperti teks dalam widget EditText) dalam Bundle (blob key-value pair) dan memulihkannya jika pengguna mengarah kembali ke aktivitas. Untuk informasi selengkapnya tentang memulihkan suatu aktivitas tempat pengguna kembali, baca Menyimpan dan memulihkan status aktivitas.

Dari status Berhenti, aktivitas akan kembali untuk berinteraksi dengan pengguna, atau aktivitas akan selesai berjalan dan hilang. Jika aktivitas kembali, sistem akan memanggil onRestart(). Jika Activity selesai berjalan, sistem akan memanggil onDestroy(). Bagian selanjutnya menjelaskan callback onDestroy().

onDestroy()

onDestroy() dipanggil sebelum aktivitas ditutup. Sistem memanggil callback ini karena:

  1. aktivitas selesai (karena pengguna benar-benar menutup aktivitas atau karena finish() dipanggil pada aktivitas tersebut), atau
  2. sistem sementara menutup aktivitas karena perubahan konfigurasi (seperti rotasi perangkat atau mode multi-jendela)

Saat aktivitas berpindah ke status ditutup, komponen berbasis siklus proses apa pun yang terkait dengan siklus proses aktivitas akan menerima peristiwa ON_DESTROY. Di sinilah komponen siklus proses dapat membersihkan apa pun yang diperlukan sebelum Aktivitas ditutup.

Alih-alih menempatkan logika di Aktivitas Anda untuk menentukan alasan aktivitas tersebut ditutup, Anda harus menggunakan objek ViewModel untuk memuat data tampilan yang relevan bagi Aktivitas Anda. Jika Aktivitas akan dibuat ulang karena adanya perubahan konfigurasi, ViewModel tidak perlu melakukan apa-apa karena itu akan dipertahankan dan diberikan ke instance Aktivitas berikutnya. Jika Aktivitas tidak akan dibuat kembali, ViewModel akan memiliki metode onCleared() yang disebut tempat aktivitas tersebut dapat membersihkan data yang diperlukan sebelum ditutup.

Anda dapat membedakan kedua skenario ini dengan metode isFinishing().

Jika aktivitas selesai, onDestroy() adalah callback siklus proses terakhir yang diterima aktivitas. Jika onDestroy() dipanggil sebagai hasil dari perubahan konfigurasi, sistem akan segera membuat instance aktivitas baru kemudian memanggil onCreate() pada instance baru dalam konfigurasi baru.

Callback onDestroy() harus melepaskan semua resource yang belum dirilis oleh callback sebelumnya seperti onStop().

Status aktivitas dan pengeluaran dari memori

Sistem menutup proses ketika perlu membebaskan RAM; kemungkinan sistem menutup proses tertentu tergantung kondisi proses pada saat itu. Pada gilirannya, status proses bergantung pada status aktivitas yang berjalan dalam proses. Tabel 1 menunjukkan korelasi antara status proses, status aktivitas, dan kemungkinan sistem menutup proses.

Kemungkinan ditutup Status proses Status aktivitas
Paling sedikit Latar depan (memiliki atau akan mendapatkan fokus) Dibuat
Dimulai
Dilanjutkan
Lainnya Latar belakang (kehilangan fokus) Dijeda
Paling banyak Latar belakang (tidak terlihat) Dihentikan
Kosong Ditutup

Tabel 1. Hubungan antara proses siklus proses dan status aktivitas

Sistem tidak pernah menutup aktivitas secara langsung untuk membebaskan memori. Namun, sistem akan menutup proses tempat aktivitas berjalan, bukan hanya menutup aktivitas tetapi juga semua hal lain yang berjalan dalam proses. Untuk mempelajari cara mempertahankan dan memulihkan status UI aktivitas Anda saat terjadi proses penghapusan yang diinisiasi sistem, baca Menyimpan dan memulihkan status aktivitas.

Seorang pengguna juga dapat menghentikan proses menggunakan Pengelola Aplikasi pada Setelan untuk menutup aplikasi yang sesuai.

Untuk informasi selengkapnya tentang proses secara umum, baca Proses dan Thread. Untuk informasi selengkapnya tentang bagaimana siklus proses suatu proses terkait dengan status aktivitas di dalamnya, baca bagian Proses Siklus Proses dari halaman itu.

Menyimpan dan memulihkan status UI sementara

Pengguna berharap status UI aktivitas tetap sama selama perubahan konfigurasi, seperti rotasi atau beralih ke mode multi-jendela. Namun, sistem menutup aktivitas secara default ketika perubahan konfigurasi tersebut terjadi, sehingga menghapus semua status UI yang disimpan dalam instance aktivitas. Demikian pula, pengguna mengharapkan status UI tetap sama jika beralih sementara dari aplikasi Anda ke aplikasi yang berbeda, lalu kembali ke aplikasi Anda nanti. Namun, sistem dapat menutup proses aplikasi saat pengguna keluar dan aktivitas dihentikan.

Jika aktivitas ditutup karena batasan sistem, Anda harus mempertahankan status UI sementara pengguna yang menggunakan kombinasi ViewModel, onSaveInstanceState(), dan/atau penyimpanan lokal. Untuk mempelajari lebih lanjut ekspektasi pengguna versus perilaku sistem, serta cara terbaik menjaga data status UI rumit di seluruh aktivitas dan penutupan proses yang diinisiasi sistem, baca Menyimpan Status UI.

Bagian ini menguraikan status instance dan cara menerapkan metode onSaveInstance(), yang merupakan callback pada aktivitas itu sendiri. Jika data UI Anda sederhana dan ringan, seperti jenis data primitif atau objek sederhana (seperti String), Anda dapat menggunakan onSaveInstanceState() sendiri untuk mempertahankan UI di kedua perubahan konfigurasi dan penutupan proses yang diinisiasi sistem. Namun, biasanya Anda harus menggunakan ViewModel dan onSaveInstanceState() (seperti yang diuraikan dalam Menyimpan Status UI) karena onSaveInstanceState() menimbulkan biaya serialisasi/deserialisasi.

Status instance

Ada beberapa skenario ketika aktivitas Anda ditutup karena perilaku aplikasi normal, seperti ketika pengguna menekan tombol Kembali atau aktivitas Anda memberi sinyal penutupannya sendiri dengan memanggil metode finish(). Setelah aktivitas Anda ditutup karena pengguna menekan Kembali atau aktivitas selesai dengan sendirinya, konsep sistem dan pengguna tentang instance Activity hilang selamanya. Dalam skenario ini, ekspektasi pengguna cocok dengan perilaku sistem dan Anda tidak memiliki pekerjaan tambahan yang harus dilakukan.

Namun, jika sistem menutup aktivitas karena batasan sistem (seperti perubahan konfigurasi atau tekanan memori), meskipun instance Activity yang sebenarnya hilang, sistem akan mengingat bahwa itu ada. Jika pengguna mencoba membuka kembali aktivitas, sistem membuat instance baru dari aktivitas tersebut menggunakan sekumpulan data yang disimpan yang menggambarkan status aktivitas saat ditutup.

Data tersimpan yang digunakan sistem untuk memulihkan status sebelumnya disebut status instance dan merupakan kumpulan key-value pair yang disimpan di objek Bundle. Secara default, sistem menggunakan status instance Bundle untuk menyimpan informasi tentang setiap objek View dalam tata letak aktivitas Anda (seperti nilai teks yang dimasukkan ke dalam widget EditText). Jadi, jika instance aktivitas Anda ditutup dan dibuat ulang, status tata letak akan dipulihkan seperti sebelumnya tanpa kode yang Anda perlukan. Akan tetapi, aktivitas Anda mungkin mempunyai lebih banyak informasi status yang ingin Anda pulihkan, seperti variabel anggota yang memantau progres pengguna dalam aktivitas tersebut.

Catatan: Supaya sistem Android memulihkan status tampilan dalam aktivitas Anda, setiap tampilan harus memiliki ID unik, yang disediakan oleh atribut android:id.

Objek Bundle tidak sesuai untuk mempertahankan lebih dari jumlah data yang sedikit karena memerlukan serialisasi pada thread utama dan menggunakan memori proses-sistem. Untuk menyimpan lebih dari jumlah data yang sangat kecil, Anda harus melakukan pendekatan gabungan untuk menjaga data, menggunakan penyimpanan lokal yang persisten, metode onSaveInstanceState(), dan class ViewModel, sebagaimana diuraikan dalam Menyimpan Status UI.

Menyimpan status UI yang sederhana dan ringan menggunakan onSaveInstanceState()

Ketika aktivitas Anda mulai berhenti, sistem akan memanggil metode onSaveInstanceState() sehingga aktivitas Anda dapat menyimpan informasi status ke bundle status instance. Implementasi default metode ini menyimpan informasi sementara tentang status hierarki tampilan aktivitas, seperti teks dalam widget EditText atau posisi scroll dari widget ListView.

Untuk menyimpan informasi status instance tambahan untuk aktivitas, Anda harus mengganti onSaveInstanceState() dan menambahkan key-value pair ke objek Bundle yang disimpan jika aktivitas Anda ditutup secara tak terduga. Jika mengganti onSaveInstanceState(), Anda harus memanggil implementasi superclass jika ingin melakukan implementasi default untuk menyimpan status hierarki tampilan. Contoh:

Kotlin

override fun onSaveInstanceState(outState: Bundle?) {
    // Save the user's current game state
    outState?.run {
        putInt(STATE_SCORE, currentScore)
        putInt(STATE_LEVEL, currentLevel)
    }

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(outState)
}

companion object {
    val STATE_SCORE = "playerScore"
    val STATE_LEVEL = "playerLevel"
}

Java

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, currentScore);
    savedInstanceState.putInt(STATE_LEVEL, currentLevel);

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

Catatan: onSaveInstanceState() tidak dipanggil ketika pengguna secara eksplisit menutup aktivitas atau dalam kasus lain ketika finish() dipanggil.

Untuk menyimpan data persisten, seperti preferensi pengguna atau data untuk database, Anda harus mengambil peluang yang sesuai ketika aktivitas Anda berada di latar depan. Jika tidak muncul peluang seperti itu, Anda harus menyimpan data tersebut selama metode onStop().

Memulihkan status UI aktivitas menggunakan status instance tersimpan

Saat aktivitas Anda dibuat kembali setelah sebelumnya ditutup, Anda dapat memulihkan status instance tersimpan dari Bundle yang diteruskan sistem ke aktivitas Anda. Baik metode callback onCreate() maupun onRestoreInstanceState() akan menerima Bundle yang sama berisi informasi status instance.

Karena metode onCreate() dipanggil apakah sistem membuat instance baru dari aktivitas Anda atau membuat ulang yang sebelumnya, Anda harus memeriksa apakah Bundle status adalah null sebelum Anda mencoba untuk membacanya. Jika statusnya null, sistem akan membuat instance baru dari aktivitas itu, bukan memulihkan instance sebelumnya yang ditutup.

Misalnya, cuplikan kode berikut ini menunjukkan cara Anda dapat memulihkan beberapa data status dalam onCreate():

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState) // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        with(savedInstanceState) {
            // Restore value of members from saved state
            currentScore = getInt(STATE_SCORE)
            currentLevel = getInt(STATE_LEVEL)
        }
    } else {
        // Probably initialize members with default values for a new instance
    }
    // ...
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance
    if (savedInstanceState != null) {
        // Restore value of members from saved state
        currentScore = savedInstanceState.getInt(STATE_SCORE);
        currentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance
    }
    // ...
}

Daripada memulihkan status selama onCreate(), Anda dapat memilih menerapkan onRestoreInstanceState(), yang dipanggil sistem setelah metode onStart(). Sistem memanggil onRestoreInstanceState() hanya jika ada status tersimpan untuk dipulihkan, sehingga Anda tidak perlu memeriksa apakah Bundle adalah null:

Kotlin

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState)

    // Restore state members from saved instance
    savedInstanceState?.run {
        currentScore = getInt(STATE_SCORE)
        currentLevel = getInt(STATE_LEVEL)
    }
}

Java

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance
    currentScore = savedInstanceState.getInt(STATE_SCORE);
    currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

Perhatian: Selalu panggil implementasi superclass onRestoreInstanceState() sehingga implementasi default dapat memulihkan status hierarki tampilan.

Melakukan navigasi antar aktivitas

Sebuah aplikasi kemungkinan akan masuk dan keluar dari suatu aktivitas, mungkin berkali-kali, selama masa aktif aplikasi. Misalnya, pengguna dapat mengetuk tombol Kembali perangkat, atau aktivitas mungkin perlu meluncurkan aktivitas yang berbeda. Bagian ini mencakup topik yang perlu Anda ketahui untuk mengimplementasikan transisi aktivitas yang berhasil. Topik-topik ini meliputi memulai aktivitas dari aktivitas lain, menyimpan status aktivitas, dan memulihkan status aktivitas.

Memulai satu aktivitas dari aktivitas lain

Aktivitas sering kali perlu memulai aktivitas lain di beberapa titik. Kebutuhan ini muncul, misalnya, ketika suatu aplikasi perlu berpindah dari layar saat ini ke layar baru.

Bergantung pada apakah aktivitas Anda menginginkan hasil kembali dari aktivitas baru yang akan dimulai, Anda memulai aktivitas baru menggunakan metode startActivity() atau startActivityForResult(). Dalam kedua kasus tersebut, Anda memasukkan objek Intent.

Objek Intent menentukan aktivitas yang tepat yang ingin Anda mulai atau menggambarkan jenis tindakan yang ingin Anda lakukan (dan sistem memilih aktivitas yang sesuai untuk Anda, yang bahkan dapat berasal dari aplikasi yang berbeda). Objek Intent juga dapat membawa sejumlah kecil data untuk digunakan oleh aktivitas yang dimulai. Untuk informasi selengkapnya tentang class Intent, lihat Intent dan Filter Intent.

startActivity()

Jika aktivitas yang baru dimulai tidak perlu menampilkan hasil, aktivitas saat ini dapat memulainya dengan memanggil metode startActivity().

Saat menangani aplikasi Anda sendiri, biasanya Anda perlu meluncurkan aktivitas yang dikenal. Misalnya, cuplikan kode berikut ini menunjukkan cara meluncurkan aktivitas yang disebut SignInActivity.

Kotlin

val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)

Java

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

Aplikasi Anda mungkin juga ingin melakukan beberapa tindakan, seperti mengirim email, pesan teks, atau pembaruan status, menggunakan data dari aktivitas Anda. Dalam hal ini, aplikasi Anda mungkin tidak memiliki aktivitasnya sendiri untuk melakukan tindakan tersebut, sehingga Anda dapat memanfaatkan aktivitas yang disediakan aplikasi lain pada perangkat, yang dapat melakukan tindakan itu untuk Anda. Inilah saatnya intent benar-benar berharga: Anda dapat membuat intent yang menjelaskan aksi yang ingin dilakukan dan sistem akan meluncurkan aktivitas yang tepat dari aplikasi lain. Jika ada beberapa aktivitas yang dapat menangani intent itu, pengguna dapat memilih aktivitas yang akan digunakan. Misalnya, jika ingin memperbolehkan pengguna mengirim pesan email, Anda dapat membuat intent berikut:

Kotlin

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

Java

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

Tambahan EXTRA_EMAIL yang ditambahkan ke intent adalah sebuah array string alamat email yang menjadi tujuan pengiriman email. Jika aplikasi email merespons intent ini, aplikasi itu akan membaca array string yang disediakan dalam tambahan dan meletakkannya dalam kolom "ke" pada formulir penulisan email. Dalam situasi ini, aktivitas aplikasi email dimulai dan jika pengguna selesai, aktivitas Anda akan dilanjutkan.

startActivityForResult()

Terkadang Anda ingin mendapatkan hasil kembali dari suatu aktivitas saat itu berakhir. Misalnya, Anda dapat memulai aktivitas yang memungkinkan pengguna memilih seseorang dalam daftar kontak; setelah berakhir, aktivitas tersebut menampilkan orang yang dipilih. Untuk melakukan ini, Anda memanggil metode startActivityForResult(Intent, int), tempat parameter bilangan bulat mengidentifikasi panggilan. ID ini dimaksudkan untuk memisahkan antara beberapa panggilan menjadi startActivityForResult(Intent, int) dari aktivitas yang sama. Ini bukan ID global dan tidak berisiko bertentangan dengan aplikasi atau aktivitas lain. Hasilnya kembali melalui metode onActivityResult(int, int, Intent) Anda.

Saat keluar, aktivitas turunan dapat memanggil setResult(int) untuk mengembalikan data ke induknya. Aktivitas turunan harus selalu menyediakan kode hasil, yang dapat menjadi hasil standar RESULT_CANCELED, RESULT_OK, atau nilai khusus apa pun mulai dari RESULT_FIRST_USER. Selain itu, aktivitas turunan dapat secara opsional menampilkan objek Intent yang berisi data tambahan yang diinginkan. Aktivitas induk menggunakan metode onActivityResult(int, int, Intent), bersama dengan ID bilangan bulat aktivitas asal yang disediakan, untuk menerima informasi.

Jika aktivitas turunan gagal karena suatu alasan, seperti error, aktivitas induk akan menerima hasil dengan kode RESULT_CANCELED.

Kotlin

class MyActivity : Activity() {
    // ...

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            // When the user center presses, let them pick a contact.
            startActivityForResult(
                    Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")),
                    PICK_CONTACT_REQUEST)
            return true
        }
        return false
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        when (requestCode) {
            PICK_CONTACT_REQUEST ->
                if (resultCode == RESULT_OK) {
                    startActivity(Intent(Intent.ACTION_VIEW, intent?.data))
                }
        }
    }

    companion object {
        internal val PICK_CONTACT_REQUEST = 0
    }
}

Java

public class MyActivity extends Activity {
     // ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked.  Here we will just display it
                 // to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

Mengoordinasikan aktivitas

Bila suatu aktivitas memulai aktivitas lain, keduanya akan mengalami transisi siklus proses. Aktivitas pertama berhenti beroperasi dan memasuki status Dijeda atau Berhenti, sedangkan aktivitas lainnya dibuat. Jika aktivitas ini membagikan data yang disimpan ke disk atau tempat lain, penting untuk dipahami bahwa aktivitas pertama tidak sepenuhnya dihentikan sebelum yang kedua dibuat. Sebaliknya, proses memulai yang kedua tumpang tindih dengan proses penghentian yang pertama.

Urutan callback siklus proses ditentukan dengan baik, terutama ketika dua aktivitas dalam proses yang sama (aplikasi) dan satu aktivitas memulai aktivitas yang lain. Berikut urutan operasi yang terjadi setelah Aktivitas A memulai Aktivitas B:

  1. Metode onPause() aktivitas A akan dieksekusi.
  2. Metode onCreate(), onStart(), dan onResume() aktivitas B dieksekusi secara berurutan. (Aktivitas B sekarang mendapatkan fokus pengguna.)
  3. Kemudian, jika Aktivitas A tidak lagi terlihat di layar, metode onStop()-nya akan dieksekusi.

Urutan callback siklus proses yang dapat diprediksi ini memungkinkan Anda mengelola transisi informasi dari satu aktivitas ke aktivitas lainnya.