Kapan harus memanggil konteks aktivitas ATAU konteks aplikasi?

265

Ada banyak posting tentang apa dua konteks ini .. Tapi saya masih belum mengerti benar

Seperti yang saya pahami sejauh ini: Masing-masing adalah turunan dari kelasnya yang berarti bahwa beberapa programmer merekomendasikan Anda untuk menggunakan this.getApplicationContext()sesering mungkin agar tidak "membocorkan" memori apa pun. Ini karena yang lain this(mendapatkan Activitykonteks contoh) menunjuk ke Activityyang sedang dihancurkan setiap kali pengguna memiringkan ponsel atau meninggalkan aplikasi dll. Yang tampaknya Pengumpul Sampah (GC) tidak menangkap dan karenanya menggunakan terlalu banyak memori ..

Tetapi adakah yang bisa membuat contoh pengkodean yang sangat bagus di mana itu adalah hal yang tepat untuk digunakan this(mendapatkan konteks dari Activityinstance saat ini ) dan konteks aplikasi akan menjadi tidak berguna / salah?

Norfeldt
sumber

Jawaban:

408

getApplicationContext()hampir selalu salah. Ms. Hackborn (antara lain) sangat eksplisit bahwa Anda hanya menggunakan getApplicationContext()ketika Anda tahu mengapa Anda menggunakan getApplicationContext()dan hanya ketika Anda perlu menggunakannya getApplicationContext().

Terus terang, "beberapa programmer" menggunakan getApplicationContext()(atau getBaseContext(), pada tingkat lebih rendah) karena pengalaman Java mereka terbatas. Mereka menerapkan kelas batin (misalnya, OnClickListeneruntuk Buttondalam Activity) dan perlu a Context. Alih-alih menggunakan MyActivity.thisuntuk mendapatkan di kelas luar ' this, mereka menggunakan getApplicationContext()atau getBaseContext()untuk mendapatkan Contextobjek.

Anda hanya menggunakan getApplicationContext()ketika Anda tahu Anda membutuhkan Contextuntuk sesuatu yang mungkin hidup lebih lama daripada kemungkinan lain yang ContextAnda miliki. Skenario meliputi:

  • Gunakan getApplicationContext()jika Anda membutuhkan sesuatu yang terkait dengan Contextitu sendiri akan memiliki ruang lingkup global. Saya menggunakan getApplicationContext(), misalnya, dalam WakefulIntentService, untuk statis yang WakeLockakan digunakan untuk layanan ini. Karena itu WakeLockstatis, dan saya perlu Contextuntuk mendapatkan PowerManageruntuk menciptakannya, itu paling aman untuk digunakan getApplicationContext().

  • Gunakan getApplicationContext()ketika Anda mengikat ke Servicedari Activity, jika Anda ingin melewati ServiceConnection(yaitu, pegangan ke ikatan) antara Activityinstance via onRetainNonConfigurationInstance(). Android secara internal melacak binding melalui ini ServiceConnectionsdan memegang referensi ke Contextsyang membuat binding. Jika Anda mengikat dari Activity, maka Activityinstance baru akan memiliki referensi ServiceConnectionyang memiliki referensi implisit ke yang lama Activity, dan yang lama Activitytidak dapat dikumpulkan sampah.

Beberapa pengembang menggunakan subkelas khusus Applicationuntuk data global mereka sendiri, yang mereka ambil via getApplicationContext(). Itu tentu saja mungkin. Saya lebih suka anggota data statis, jika tanpa alasan lain Anda hanya dapat memiliki satuApplication objek kustom . Saya membangun satu aplikasi menggunakan Applicationobjek kustom dan merasa sangat menyakitkan. Ibu Hackborn juga setuju dengan posisi ini .

Berikut adalah alasan mengapa tidak digunakan di getApplicationContext()mana pun Anda pergi:

  • Itu tidak lengkap Context, mendukung semua yang Activitydilakukannya. Berbagai hal yang akan Anda coba lakukan Contextakan gagal, sebagian besar terkait dengan GUI .

  • Itu dapat membuat kebocoran memori, jika Contextdari getApplicationContext()memegang sesuatu yang dibuat oleh panggilan Anda di atasnya bahwa Anda tidak membersihkan. Dengan Activity, jika itu memegang sesuatu, begitu Activitysampah dikumpulkan, segala sesuatu yang lain akan keluar juga. The Applicationobjek tetap untuk masa proses Anda.

CommonsWare
sumber
1
Terima kasih banyak atas jawaban ini. Tautan lain yang saya temukan sebelum saya membaca jawaban ini mungkin juga membantu beberapa orang. stackoverflow.com/questions/7298731/… - tautan ini menjelaskan kekhawatiran saya tentang kebocoran memori.
Norfeldt
27
@Norfeldt: FYI, tautan di komentar Anda menghubungkan kembali ke jawaban ini.
CommonsWare
2
terima kasih .. ini adalah tautannya: stackoverflow.com/questions/5796611/... ini menggambarkan kebocoran memori yang saya takuti dengan menggunakan ini
Norfeldt
6
@djaqeel: Bagian terakhir dari kutipan Anda hampir benar. Itu lebih baik diutarakan sebagai "jangan memberikan konteks Kegiatan untuk sesuatu yang akan hidup lebih lama daripada Kegiatan akan, seperti anggota data statis". Namun, Anda masih menggunakan hanya getApplicationContext()ketika Anda tahu persis mengapa Anda membutuhkannya dalam situasi tertentu. Menggembungkan tata letak? Gunakan aktivitas. Mengikat ke layanan, di mana Anda memerlukannya untuk bertahan dari perubahan konfigurasi? Gunakan getApplicationContext(), jadi ikatannya tidak terikat dengan Activityinstance.
CommonsWare
7
@Sever: Saya membahas hal ini dalam jawaban saya. Dave Smith juga memiliki konteks posting blog yang luar biasa: doubleencore.com/2013/06/context Paragraf ringkasannya: "Dalam kebanyakan kasus, gunakan Konteks yang tersedia langsung untuk Anda dari komponen penutup tempat Anda bekerja. Anda dapat dengan aman memegang referensi untuk itu selama referensi itu tidak melampaui siklus hidup komponen itu. Segera setelah Anda perlu menyimpan referensi ke Konteks dari objek yang hidup di luar Aktivitas atau Layanan Anda, bahkan untuk sementara, alihkan referensi yang Anda simpan ke konteks aplikasi. "
CommonsWare
48

Saya pikir ada banyak hal yang kurang didokumentasikan di situs SDK, ini salah satunya. Klaim yang akan saya ajukan adalah sepertinya lebih baik menggunakan konteks aplikasi secara default dan hanya menggunakan konteks aktivitas saat Anda benar-benar perlu. Satu-satunya tempat di mana saya pernah melihat bahwa Anda memerlukan konteks aktivitas adalah untuk dialog kemajuan. SBERG412 mengklaim bahwa Anda harus menggunakan konteks aktivitas untuk pesan bersulang, namun dokumen Android jelas menunjukkan konteks aplikasi yang sedang digunakan. Saya selalu menggunakan konteks aplikasi untuk bersulang karena contoh Google ini. Jika itu salah, maka Google menjatuhkan bola di sini.

Berikut ini lebih banyak untuk dipikirkan dan ditinjau:

Untuk pesan roti panggang, Panduan Pengembang Google menggunakan konteks aplikasi dan secara eksplisit mengatakan untuk menggunakannya: Pemberitahuan Toast

Di bagian dialog panduan Dev, Anda melihat bahwa AlertDialog.Builder menggunakan konteks aplikasi, dan kemudian bilah kemajuan menggunakan konteks aktivitas. Ini tidak dijelaskan oleh Google. Dialog

Sepertinya alasan yang baik untuk menggunakan konteks aplikasi adalah ketika Anda ingin menangani perubahan konfigurasi seperti perubahan orientasi, dan Anda ingin mempertahankan objek yang memerlukan konteks seperti Views. Jika Anda melihat di sini: Run Time Changes Ada peringatan tentang menggunakan konteks aktivitas, yang dapat membuat kebocoran. Ini dapat dihindari dengan konteks aplikasi dengan pandangan yang harus dipertahankan (setidaknya itulah pemahaman saya). Dalam sebuah aplikasi yang saya tulis, saya bermaksud menggunakan konteks aplikasi karena saya mencoba untuk menahan beberapa pandangan dan hal-hal lain pada perubahan orientasi, dan saya masih ingin aktivitas dihancurkan dan diciptakan kembali pada perubahan orientasi. Jadi saya harus menggunakan konteks aplikasi untuk tidak menyebabkan kebocoran memori (lihat Menghindari Kebocoran memori). Bagi saya sepertinya ada banyak alasan bagus untuk menggunakan konteks aplikasi alih-alih konteks aktivitas, dan bagi saya sepertinya Anda akan lebih sering menggunakannya daripada konteks aktivitas. Itulah yang tampaknya dilakukan oleh banyak buku Android, dan itulah yang dilakukan oleh banyak contoh Google.

Dokumentasi Google benar-benar membuatnya tampak seperti menggunakan konteks aplikasi baik-baik saja dalam kebanyakan kasus, dan pada kenyataannya muncul lebih sering daripada menggunakan konteks aktivitas dalam contoh mereka (setidaknya contoh yang saya lihat). Jika benar-benar masalah untuk menggunakan konteks aplikasi, maka Google benar-benar perlu lebih menekankan hal ini. Mereka perlu menjelaskan, dan mereka perlu mengulang beberapa contoh mereka. Saya tidak akan menyalahkan ini sepenuhnya pada pengembang yang tidak berpengalaman karena otoritas (Google) benar-benar membuatnya tampak seperti itu bukan masalah untuk menggunakan konteks aplikasi.

Andi Jay
sumber
5
Saya sangat setuju. Jawaban CommonsWare sedikit mengejutkan bagi saya. Saya senang saya menemukan pertanyaan ini, karena dokumentasi Google menunjukkan bahwa menggunakan getApplicationContext bisa sangat berbahaya.
Steve Schwarcz
38

Saya menggunakan tabel ini sebagai panduan kapan harus menggunakan berbagai jenis Konteks seperti konteks Aplikasi (yaitu:) getApplicationContext()dan konteks aktivitas , juga konteks BroadcastReceiver :

masukkan deskripsi gambar di sini

Semua pahala pergi ke penulis asli di sini untuk info lebih lanjut.

CommonSenseCode
sumber
11

Konteks mana yang digunakan?

Ada dua jenis Konteks:

  1. Konteks aplikasi dikaitkan dengan aplikasi dan akan selalu sama sepanjang umur aplikasi - tidak berubah. Jadi jika Anda menggunakan Toast, Anda dapat menggunakan konteks aplikasi atau bahkan konteks aktivitas (keduanya) karena roti panggang dapat ditampilkan dari mana saja dengan aplikasi Anda dan tidak dilampirkan ke jendela tertentu. Tetapi ada banyak pengecualian, satu pengecualian adalah ketika Anda perlu menggunakan atau melewati konteks aktivitas.

  2. Konteks aktivitas dikaitkan dengan aktivitas dan dapat dihancurkan jika aktivitas tersebut dihancurkan - mungkin ada beberapa aktivitas (lebih dari kemungkinan) dengan satu aplikasi. Dan kadang-kadang Anda benar-benar membutuhkan pegangan konteks aktivitas. Misalnya, jika Anda meluncurkan aktivitas baru, Anda perlu menggunakan konteks aktivitas di Intentnya sehingga aktivitas peluncuran baru terhubung ke aktivitas saat ini dalam hal tumpukan aktivitas. Namun, Anda dapat menggunakan konteks aplikasi juga untuk meluncurkan aktivitas baru, tetapi kemudian Anda harus menetapkan flag Intent.FLAG_ACTIVITY_NEW_TASKuntuk memperlakukannya sebagai tugas baru.

Mari kita pertimbangkan beberapa kasus:

  • MainActivity.this merujuk ke konteks MainActivity yang memperluas kelas Activity tetapi kelas dasar (activity) juga memperluas kelas Context, sehingga dapat digunakan untuk menawarkan konteks aktivitas.

  • getBaseContext() menawarkan konteks aktivitas.

  • getApplication() menawarkan konteks aplikasi.

  • getApplicationContext() juga menawarkan konteks aplikasi.

Untuk informasi lebih lanjut silakan periksa tautan ini .

Zohra Khan
sumber
Bagaimana dengan kasus di mana orang perlu menampilkan AlertDialog di aplikasi misalnya proses async yang menunjukkan hasil. Contohnya mungkin : pengguna mengklik unduhan, ini akan mengaktifkan permintaan unduhan downloadmanager, dan ketika sinyal selesai diterima, itu akan menampilkan dialog misalnya "Apa yang ingin Anda lakukan dengan unduhan ini?". Solusi (peretasan) saya menyimpan yang terbaru Activitydi static Applicationkelas, dan meminta yang terbaru Activitysaat unduhan selesai. Namun, saya ragu ini adalah implementasi yang tepat. TL; DR Bagaimana cara menampilkan AlertDialog di mana saja di aplikasi?
CybeX
@KGCybeX Jika Anda ingin menampilkan apa saja dan di mana saja di aplikasi Anda ketika unduhan selesai, Anda harus mendaftarkan penerima siaran secara manual pada aktivitas Anda yang mendengarkan pesan tertentu yang akan disiarkan layanan unduhan Anda dan melakukan apa pun yang Anda inginkan setelah menerima pesan, atau melampirkan aktivitas Anda ke layanan itu secara langsung.
ExiRouS
6

Saya bertanya-tanya mengapa tidak menggunakan Konteks Aplikasi untuk setiap operasi yang didukungnya. Pada akhirnya itu menurunkan kemungkinan kebocoran memori dan tidak ada pemeriksaan nol untuk getContext () atau getActivity () (saat menggunakan konteks aplikasi yang diinjeksi atau diperoleh melalui metode statis dari Aplikasi). Pernyataan, seperti yang dibuat oleh Ms. Hackborn untuk menggunakan Konteks Aplikasi hanya jika diperlukan, sepertinya tidak meyakinkan bagi saya tanpa penjelasan mengapa. Tetapi tampaknya saya telah menemukan alasan yang tidak patut untuk dipikirkan:

telah menemukan bahwa ada masalah pada beberapa kombinasi versi Android / perangkat yang tidak mengikuti aturan ini. Misalnya, jika saya memiliki BroadcastReceiver yang meneruskan sebuah Konteks dan saya mengonversi Konteks itu menjadi Konteks Aplikasi dan kemudian mencoba memanggil registerReceiver () pada Konteks Aplikasi ada banyak contoh di mana ini berfungsi dengan baik, tetapi juga banyak contoh di mana saya mendapatkan crash karena ReceiverCallNotAllowedException. Kecelakaan ini terjadi pada berbagai versi Android dari API 15 hingga 22. https://possiblemobile.com/2013/06/context/#comment-2443283153

Karena itu tidak dijamin bahwa semua operasi yang digambarkan didukung oleh Konteks Aplikasi pada tabel di bawah ini akan berfungsi pada semua perangkat Android! masukkan deskripsi gambar di sini

Malachiasz
sumber
4

Dua contoh hebat tentang kapan Anda harus menggunakan konteks Aktivitas vs. konteks Aplikasi adalah ketika menampilkan pesan Toast atau pesan Dialog bawaan ketika menggunakan konteks Aplikasi akan menyebabkan pengecualian:

ProgressDialog.show(this, ....);

atau

Toast t = Toast.makeText(this,....);

Kedua hal ini memerlukan informasi dari konteks Aktivitas yang tidak disediakan dalam konteks Aplikasi.

SBerg413
sumber
5
Hm .. Versi OS Android apa yang Anda uji? Saya sudah menguji pada 4.4.4 dan bekerja dengan baik. Plus, seperti yang disebutkan @Andi Jay, dokumen pengembang Android resmi menggunakan konteks aplikasi dalam kode sampel mereka. developer.android.com/guide/topics/ui/notifiers/…
김준호
1
@Cina nama, ya itu mungkin berfungsi tetapi suatu saat di masa depan aplikasi itu, itu juga akan crash. Terjadi pada saya beberapa kali.
Ojonugwa Jude Ochalifu
1
Ketika saya menggunakan konteks Aktivitas di Toast, itu bocor memori!
Jemshit Iskenderov
3

Konteks aplikasi hidup sampai aplikasi Anda hanya hidup dan itu tidak tergantung pada Siklus Hidup Aktivitas tetapi, konteks menjaga objek berumur panjang . Jika objek yang Anda gunakan sementara, waktu itu menggunakan Konteks Aplikasi dan Konteks Aktivitas digunakan sama sekali berlawanan dengan Konteks Aplikasi.

Ganesh Katikar
sumber