getApplication () ve getApplicationContext () karşılaştırması


417

Buna tatmin edici bir cevap bulamadım, işte başlıyoruz: Anlaşma nedir Activity/Service.getApplication()ve Context.getApplicationContext()?

Bizim uygulamamızda, her ikisi de aynı nesneyi döndürür. Bir In ActivityTestCaseancak, uygulamayı alay yapacak getApplication()taklidinin ile geri gelmek, ama getApplicationContextyine de farklı bir bağlam örneği (Android tarafından enjekte bir) dönecektir. Bu bir hata mı? Bilerek mi?

İlk etapta farkı bile anlamıyorum. Test paketinin dışında, her iki aramanın da farklı nesnelerle geri gelebileceği durumlar var mı? Ne zaman ve neden? Dahası, neden getApplicationtanımlanmış Activityve Serviceaçık değil Context? Her zaman her yerden geçerli bir uygulama örneği olmamalı mı ?


8
Güzel soru. Test işleri biraz gizem (bildiğiniz gibi). Bu iki yöntem çağrıları herhangi bir farklılık tezahür kendisi eğer Ama acaba yok açıkça bir oluşturmak Applicationuygulamanızda nesneyi.
Christopher Orr

Yanıtlar:


366

Çok ilginç bir soru. Bence bu çoğunlukla anlamsal bir anlam ve tarihsel nedenlerden de kaynaklanıyor olabilir.

Mevcut Android Etkinlik ve Hizmet uygulamalarında getApplication()ve getApplicationContext()aynı nesneyi döndürmesine rağmen, bunun her zaman böyle olacağının garantisi yoktur (örneğin, belirli bir satıcı uygulamasında).

Bu nedenle, Manifest'te kaydettiğiniz Application sınıfını istiyorsanız, onu asla çağırmamalı getApplicationContext()ve uygulamanıza yayınlamamalısınız, çünkü uygulama örneği olmayabilir (test çerçevesi ile açıkça deneyimlediğiniz).

Neden getApplicationContext()ilk etapta var?

getApplication()getApplicationContext()Context sınıfında bildirilirken , yalnızca Activity sınıfında ve Service sınıfında kullanılabilir.

Bu aslında bir şey anlamına gelir: bir bağlamda olmayan ancak onReceive yönteminde bir bağlam verilen bir yayın alıcısına kod yazarken, yalnızca arayabilirsiniz getApplicationContext(). Bu ayrıca bir BroadcastReceiver'da uygulamanıza erişiminizin garanti edilmediği anlamına gelir.

Android koduna bakarken, eklendiğinde bir etkinliğin temel bir bağlam ve bir uygulama aldığını ve bunların farklı parametreler olduğunu görürsünüz. getApplicationContext()delege çağırıyor baseContext.getApplicationContext().

Bir şey daha var: Belgeler çoğu durumda bunun Alt Sınıfı uygulaması gerekmemesi gerektiğini söylüyor:

Normalde alt sınıfa gerek yoktur Application. Çoğu durumda, statik tek tonlar aynı işlevselliği daha modüler bir şekilde sağlayabilir. Eğer singleton'unuz global bir bağlama ihtiyaç duyarsa (örneğin yayın alıcılarını kaydetmek için), onu alma fonksiyonuna , singletonu ilk oluştururken Contextdahili olarak kullanılan bir fonksiyon verilebilir Context.getApplicationContext().

Bunun kesin ve kesin bir cevap olmadığını biliyorum, ama yine de bu sorunuza cevap veriyor mu?


89
@ Piwaï: Dokümanı dinleme. Alt sınıflama android.app.Applicationsüper yardım dolu. Örneğin, veritabanını başlatırken sonsuz sorun yaşadım. Bir kez taşındı Application.onCreatebir cazibe gibi çalıştı. Şimdi tüm sistem çapında başlatma yapmak Applicationve olmadan başka bir App yazmak olmaz.
Martin

9
@Martin Dokümanları dinlememek genellikle kodunuzun gelecekte kırılması, hatta şimdi beklenmedik koşullar altında taşınabilmesi, taşınabilirliğin kaybedilmesi, kötü performans göstermesi, platform geliştiricilerinin yararlı bir değişiklik yapmasını engellemesi anlamına gelir (bu, yanlış olmasına rağmen yanlış yaptığınız varsayımı ihlal eder) dokümanlara değil, yalnızca geçerli uygulamaya dayalı). Bunun oldukça kötü bir davranış ve oldukça kötü bir tavsiye olduğunu düşünüyorum.
Palec

17
@Palec: “Uygulamayı alt sınıfa ayırmaya gerek yoktur.” - Bu sadece ipucu. Hala resmi olarak belgelenmiş işlevselliği amaçlanan şekilde kullanıyorum. - Ben başlangıçta bu “statik tekilleri” kullanıyordum ve a… tembel başlangıcın acıları olduğu ortaya çıktı. Özellikle enstrümantasyon testleri ile kullanıldığında. - Hala modülerlik için bu Singletons var ama ben bir android.app.Application alt sınıfının onCreate en blokta onları somutlaştırmak. - tıkır tıkır çalışıyor.
Martin

9
@Martin bunu açıkça belirtmeliydim: Tepkim yalnızca ilk cümle ile ilgiliydi. "Dokümanı dinleme." Bu genellikle çok tehlikeli bir tavsiye parçasıdır. Ama “Bu sadece bir ipucu - eğer bir sebebin varsa dokümanı görmezden gelebilirsin ve sana bir tane göstereceğim…” kulağa kesinlikle iyi geliyor.
Palec

3
msgstr "" "Bağlam olmayan ancak onReceive yönteminde bir bağlam verilen bir yayın alıcısına kod yazarken, yalnızca getApplicationContext () yöntemini çağırabilirsiniz. " .Yani BroadcastReceiver'daki uygulama sınıfıma erişmek için ne yapabiliriz?
Dr.jacky

30

Karşılaştır getApplication()ve getApplicationContext().

getApplicationBir döndürür ApplicationAşağıdaki gibi bazı cihaz durumlara global uygulama durumunu ve cevap yönetmenize izin verir nesneyi onLowMemory()ve onConfigurationChanged().

getApplicationContextglobal uygulama bağlamını döndürür - diğer bağlamlardan farkı, örneğin, bir etkinlik bağlamının, etkinliğiniz sona erdiğinde Android tarafından yok edilebilir (veya kullanılamaz hale getirilebilir) olmasıdır. Uygulama bağlamınız (belirli bir Activityşeye bağlı olmayan) mevcutken Uygulama bağlamı kullanılabilir durumda kalır, böylece bunu daha uzun süreler boyunca kullanılabilir olacak ve geçici UI nesnelerinden bağımsız bir bağlam gerektiren Bildirimler gibi şeyler için kullanabilirsiniz .

Bu kod aynı olabilir ya da olmayabilir olsun ne yapıyor bağlıdır sanırım - normal kullanımda olsa, ben onları farklı olmasını beklenir.


19
ancak Application olduğu bir Context(o devralır) ve zamanında, her iki yöntem de aynı örneği döndürür. Peki fark nedir?
Matthias

3
Fark kapsamdır. Uygulama içeriğiniz, örneğin bir Etkinlik içeriğinden çok daha uzun süre geçerli olacaktır, çünkü etkinliğiniz yalnızca çok kısa bir süre kullanımda olabilirken, Uygulamanız birçok Etkinlikten oluşabilir. Etkinlik Bağlamınız en azından ilk etkinlik başlatıldığında başlayan ve son etkinlik sona erdiğinde sürecektir. Hepsi Bağlamdır, ancak biri daha uzun ömürlüdür ve değişmez, ancak diğerleri kısa ömürlüdür ve farklı örnekler farklı Bağlamlara sahip olabilir.
RivieraKid

16
Sanırım sorumu yanlış anlıyor olabilirsiniz. ActivityBağlam ve bağlam arasındaki farkı sormuyorum Application. Application(Küresel, benzersiz uygulama bağlamı) ve getApplicationContextgeri gelenler arasındaki farkı düşünüyorum . İkincisi aslında Android 1.6'dan önce işlevsel değildi; her zaman geri dönerdi null.
Matthias

1
@Matthias Bence hala geçerli. Bağlam Android sisteminin kendisi tarafından enjekte edilir (uygulanır), Uygulama Bağlam'ı devralır ve genişletir. Uygulama sınıfı (sizin tarafınızdan söylendiği gibi) kolayca alay edilebilir, o zaman Uygulama sınıfının bunu başarmak için bazı "sihir" (test projesinde) yaptığını ve muhtemelen enjekte edilen Bağlamı görmezden geldiğini gösteren güvenli bir bahis değil mi?
Audrius

3
Tekrar gel? Üzgünüm, hala soruma nasıl cevap verdiğini göremiyorum.
Matthias

30

Bağlam sarma ile ilgili gibi görünüyor. Türetilmiş sınıfların çoğu Context, aslında ContextWrapperbaşka bir bağlam için, muhtemelen sarıcı tarafından yapılan değişikliklerle temsil edilen bir sınıftır .

Bağlam alay ve proxy yapmayı destekleyen genel bir soyutlamadır. Birçok bağlam, a gibi sınırlı bir ömür boyu nesneye bağlı olduğundan Activity, gelecekteki bildirimlere kaydolma gibi amaçlar için daha uzun ömürlü bir bağlam elde etmenin bir yolu olmalıdır. Bu ile elde edilir Context.getApplicationContext(). Mantıksal bir uygulama genel Applicationnesneyi döndürmektir , ancak hiçbir şey bir bağlam uygulamasının uygun bir yaşam süresine sahip bir sarıcı veya proxy döndürmesini engellemez.

Etkinlikler ve hizmetler daha spesifik olarak bir Applicationnesneyle ilişkilendirilir . Bunun faydası, inanıyorum oluşturabilir ve türetilmiş tezahür özel bir sınıfta kayıt olmasıdır Applicationve emin olmak Activity.getApplication()veya Service.getApplication()size türetilmiş yayın yapabilirsiniz bu özel tip, o belirli nesne dönecektir Applicationne olursa olsun sınıf ve kullanım özel amaçlı.

Başka bir deyişle, getApplication()bir Applicationnesneyi döndürmek garanti edilirken getApplicationContext(), bunun yerine bir proxy döndürmek ücretsizdir.


"Bağlam alaycılığı ve proxy oluşturmayı destekleyen genel bir soyutlama" derken, tam olarak "proxy oluşturma" ile ne demek istiyorsun? Beni bazı referanslara yönlendirir misiniz? Bağlamın tamamını oldukça kıvrımlı buluyorum.
Tiago

@Tiago Bu cevap daha iyi anlamanıza yardımcı olabilir: stackoverflow.com/questions/10641144/…
superuser

-13

Soruyu cevaplamak için getApplication () bir Application nesnesi ve getApplicationContext () bir Context nesnesi döndürür. Kendi gözlemlerinize dayanarak, her ikisinin de Bağlamının aynı olduğunu varsayacağım (yani, Uygulama sınıfının, temel sınıfın Bağlam kısmını doldurmak için ikinci işlevi çağırdığı veya eşdeğer bir eylemin gerçekleştiği sahnelerin arkasında). Sadece bir bağlama ihtiyacınız varsa hangi işlevi çağırdığınızın bir önemi yoktur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.