getApplication () vs. getApplicationContext ()

417

Saya tidak dapat menemukan jawaban yang memuaskan untuk ini, jadi di sini kita mulai: apa masalahnya Activity/Service.getApplication()dan Context.getApplicationContext()?

Dalam aplikasi kita, keduanya mengembalikan objek yang sama. Dalam ActivityTestCaseNamun, mengejek aplikasi akan membuat getApplication()datang kembali dengan pura-pura, tapi getApplicationContextmasih akan kembali contoh konteks yang berbeda (satu disuntikkan oleh Android). Apakah itu bug? Apakah itu disengaja?

Saya bahkan tidak mengerti perbedaannya. Apakah ada case di luar test suite di mana kedua panggilan dapat kembali dengan objek yang berbeda? Kapan dan mengapa? Selain itu, mengapa getApplicationdidefinisikan Activitydan Service, tetapi tidak pada Context? Bukankah seharusnya selalu ada contoh aplikasi yang valid tersedia dari mana saja ?

Matthias
sumber
8
Pertanyaan yang bagus Hal-hal pengujian adalah sedikit misteri (seperti yang Anda ketahui). Tapi saya ingin tahu apakah ada perbedaan yang muncul dalam dua metode ini jika Anda tidak secara eksplisit membuat Applicationobjek di aplikasi Anda.
Christopher Orr

Jawaban:

366

Pertanyaan yang sangat menarik. Saya pikir itu terutama makna semantik, dan mungkin juga karena alasan historis.

Meskipun dalam implementasi Aktivitas dan Layanan Android saat ini, getApplication()dan getApplicationContext()mengembalikan objek yang sama, tidak ada jaminan bahwa ini akan selalu menjadi kasus (misalnya, dalam implementasi vendor tertentu).

Jadi, jika Anda ingin kelas Aplikasi yang Anda daftarkan di Manifest, Anda tidak boleh memanggil getApplicationContext()dan melemparkannya ke aplikasi Anda, karena itu mungkin bukan instance aplikasi (yang jelas-jelas Anda alami dengan kerangka tes).

Mengapa getApplicationContext()ada di tempat pertama?

getApplication()hanya tersedia di kelas Aktivitas dan kelas Layanan, sedangkan getApplicationContext()dinyatakan dalam kelas Konteks.

Itu sebenarnya berarti satu hal: ketika menulis kode di penerima siaran, yang bukan konteks tetapi diberi konteks dalam metode onReceive, Anda hanya dapat menelepon getApplicationContext(). Yang juga berarti bahwa Anda tidak dijamin memiliki akses ke aplikasi Anda di BroadcastReceiver.

Saat melihat kode Android, Anda melihat bahwa ketika dilampirkan, suatu kegiatan menerima konteks dasar dan aplikasi, dan itu adalah parameter yang berbeda. getApplicationContext()delegasi itu panggilan untuk baseContext.getApplicationContext().

Satu hal lagi: dokumentasi mengatakan bahwa itu sebagian besar kasus, Anda tidak perlu subkelas Aplikasi:

Biasanya tidak perlu subclass Application. Dalam sebagian besar situasi, lajang statis dapat menyediakan fungsionalitas yang sama dengan cara yang lebih modular. Jika singleton Anda membutuhkan konteks global (misalnya untuk mendaftarkan penerima siaran), fungsi untuk mengambilnya dapat diberikan Contextyang digunakan secara internal Context.getApplicationContext()saat pertama kali membangun singleton.

Saya tahu ini bukan jawaban yang tepat dan tepat, tetapi tetap saja, apakah itu menjawab pertanyaan Anda?

Pierre-Yves Ricau
sumber
89
@ Piwaï: Jangan dengarkan dokter. Subclassing android.app.Applicationsangat membantu penuh. Sebagai contoh, saya punya masalah tak berujung menginisialisasi database. Setelah pindah ke Application.onCreatesana bekerja seperti pesona. Sekarang saya melakukan inisialisasi seluruh sistem Applicationdan saya tidak akan menulis Aplikasi lain tanpa.
Martin
9
@ Martin Tidak mendengarkan dokumen pada umumnya berarti bahwa kode Anda mungkin rusak di masa depan, atau bahkan sekarang dalam kondisi yang tidak terduga, kehilangan portabilitas, berkinerja buruk, mencegah pengembang platform melakukan perubahan yang menguntungkan (yang mematahkan asumsi yang Anda buat secara salah meskipun itu adalah hanya didasarkan pada implementasi saat ini, bukan pada dokumen). Saya pikir ini adalah perilaku yang sangat buruk dan nasihat yang sangat buruk.
Palec
17
@Palec: "Biasanya tidak perlu untuk subkelas Aplikasi." - Itu hanya petunjuk. Saya masih menggunakan fungsionalitas yang didokumentasikan secara resmi dengan cara yang dimaksud. - Saya dulu menggunakan "lajang statis" di awal dan mereka ternyata menyebalkan di ... - inisialisasi malas memiliki masalah. Terutama ketika digunakan dengan tes instrumentasi. - Saya masih memiliki Singletons untuk modularitas tapi saya instantiate mereka en block di onCreate dari subclass android.app.Application. - Bekerja seperti pesona.
Martin
9
@ Martin Harusnya saya jelaskan: Reaksi saya hanya menyangkut kalimat pertama. "Jangan dengarkan dokter." Ini umumnya nasihat yang sangat berbahaya. Tapi "Ini hanya sebuah petunjuk - Anda dapat mengabaikan dokter dalam kasus ini jika Anda memiliki alasan dan saya akan menunjukkan satu ..." kedengarannya benar-benar oke untuk saya.
Palec
3
"ketika menulis kode pada penerima siaran, yang bukan konteks tetapi diberi konteks dalam metode onReceive, Anda hanya dapat memanggil getApplicationContext (). Yang juga berarti Anda TIDAK dijamin memiliki akses ke aplikasi Anda dalam BroadcastReceiver. " .Jadi apa yang bisa kita lakukan untuk mengakses kelas aplikasi saya di BroadcastReceiver?
Dr.jacky
30

Bandingkan getApplication()dan getApplicationContext().

getApplicationmengembalikan Applicationobjek yang akan memungkinkan Anda untuk mengelola keadaan aplikasi global Anda dan menanggapi beberapa situasi perangkat seperti onLowMemory()dan onConfigurationChanged().

getApplicationContextmengembalikan konteks aplikasi global - perbedaan dari konteks lain adalah bahwa misalnya, konteks aktivitas dapat dihancurkan (atau jika tidak tersedia) oleh Android ketika aktivitas Anda berakhir. Konteks Aplikasi tetap tersedia selama objek Aplikasi Anda ada (yang tidak terikat pada spesifik Activity) sehingga Anda dapat menggunakan ini untuk hal-hal seperti Pemberitahuan yang memerlukan konteks yang akan tersedia untuk jangka waktu yang lebih lama dan independen dari objek UI sementara.

Saya kira itu tergantung pada apa kode Anda lakukan apakah ini mungkin atau mungkin tidak sama - meskipun dalam penggunaan normal, saya berharap mereka berbeda.

RivieraKid
sumber
19
tetapi Application adalah sebuah Context(mewarisi dari itu), dan pada saat runtime, kedua metode kembali contoh yang sama. Jadi apa bedanya?
Matthias
3
Perbedaannya adalah ruang lingkup. Konteks Aplikasi Anda akan valid jauh lebih lama daripada, katakanlah, konteks Aktivitas karena aktivitas tersebut hanya dapat digunakan untuk waktu yang sangat singkat, sedangkan Aplikasi Anda dapat terdiri dari banyak Kegiatan. Konteks Aktivitas Anda akan valid setidaknya selama durasi yang dimulai ketika aktivitas pertama dimulai dan berakhir ketika aktivitas terakhir. Mereka semua adalah Konteks, tetapi yang satu lebih tahan lama dan tidak berubah, tetapi yang lain berumur pendek, dan contoh yang berbeda mungkin memiliki Konteks yang berbeda.
RivieraKid
16
Saya pikir Anda mungkin salah membaca pertanyaan saya. Saya tidak meminta perbedaan antara Activitykonteks dan Applicationkonteks. Saya sedang mempertimbangkan perbedaan antara Application(yang merupakan konteks aplikasi global dan unik) dan apa pun yang getApplicationContextdikembalikan. Yang terakhir itu sebenarnya non-fungsional sebelum Android 1.6; dulu selalu kembali null.
Matthias
1
@Matthias Menurut saya itu masih relevan. Konteks disuntikkan (diimplementasikan) oleh sistem Android itu sendiri, sementara Aplikasi mewarisi dan memperluas Konteks. Kelas aplikasi dapat dengan mudah diejek (seperti yang Anda katakan) maka bukankah itu merupakan taruhan yang aman bahwa itu menunjukkan bahwa kelas Aplikasi melakukan beberapa "sihir" (dalam proyek uji) untuk mencapainya, mungkin mengabaikan Konteks yang disuntikkan?
Audrius
3
Datang lagi? Maaf, saya masih tidak melihat bagaimana jawaban pertanyaan saya.
Matthias
30

Tampaknya ada hubungannya dengan pembungkus konteks. Sebagian besar kelas berasal dari Contextsebenarnya ContextWrapper, yang pada dasarnya mendelegasikan ke konteks lain, mungkin dengan perubahan oleh pembungkus.

Konteksnya adalah abstraksi umum yang mendukung ejekan dan proksi. Karena banyak konteks terikat pada objek seumur hidup terbatas seperti Activity, maka perlu ada cara untuk mendapatkan konteks yang berumur panjang, untuk tujuan seperti mendaftar untuk pemberitahuan di masa mendatang. Itu dicapai oleh Context.getApplicationContext(). Implementasi logis adalah mengembalikan Applicationobjek global , tetapi tidak ada yang mencegah implementasi konteks dari mengembalikan pembungkus atau proksi dengan masa hidup yang sesuai sebagai gantinya.

Aktivitas dan layanan lebih khusus dikaitkan dengan suatu Applicationobjek. Kegunaan dari ini, saya percaya, adalah bahwa Anda dapat membuat dan mendaftar dalam manifes kelas kustom yang berasal dari Applicationdan memastikan bahwa Activity.getApplication()atau Service.getApplication()akan mengembalikan objek spesifik dari tipe tertentu itu, yang dapat Anda lemparkan ke Applicationkelas turunan Anda dan gunakan untuk apa pun tujuan khusus.

Dengan kata lain, getApplication()dijamin untuk mengembalikan Applicationobjek, sementara getApplicationContext()bebas untuk mengembalikan proxy.

usethe4ce
sumber
Ketika Anda mengatakan "konteksnya adalah abstraksi umum yang mendukung ejekan dan proksi" apa yang Anda maksud dengan "proksi" sebenarnya? Bisakah Anda mengarahkan saya ke beberapa referensi? Saya menemukan keseluruhan Konteks sangat berbelit-belit.
Tiago
@Tiago Jawaban ini dapat membantu Anda memahami lebih baik: stackoverflow.com/questions/10641144/…
superuser
-13

Untuk menjawab pertanyaan, getApplication () mengembalikan objek Aplikasi dan getApplicationContext () mengembalikan objek Konteks. Berdasarkan pengamatan Anda sendiri, saya akan berasumsi bahwa Konteks keduanya identik (yaitu di belakang layar kelas Aplikasi memanggil fungsi yang terakhir untuk mengisi bagian Konteks dari kelas dasar atau beberapa tindakan setara terjadi). Seharusnya tidak terlalu penting fungsi mana yang Anda panggil jika Anda hanya memerlukan sebuah Konteks.

Lenny Porter
sumber