Etkinlik bağlamı VEYA uygulama bağlamı ne zaman çağrılır?


265

Bu iki bağlamın ne olduğu hakkında pek çok şey yayınlandı .. Ama hala pek doğru bulmuyorum

Şimdiye kadar anladığım kadarıyla: Her biri kendi sınıfının bir örneğidir, bu da bazı programcıların this.getApplicationContext()herhangi bir hafızayı "sızdırmamak" için mümkün olduğunca sık kullanmanızı önerir . Bunun nedeni, diğer this( Activityörnek bağlamı alma ) Activity, kullanıcının telefonu her yatırdığında veya uygulamadan ayrıldığında vb. Yok edilen bir öğeye işaret etmesidir. ..

Ancak, lütfen kullanmak için doğru olanın this(mevcut Activityörneğin bağlamını alma ) ve uygulama bağlamının yararsız / yanlış olacağı gerçekten iyi kodlama örnekleri bulabilir mi?

Yanıtlar:


408

getApplicationContext()neredeyse her zaman yanlıştır. Bayan Hackborn (diğerleri arasında) bu çok açık olmuştur sadece kullanmak getApplicationContext()Bildiğiniz zaman niye kullandığınız getApplicationContext()ve sadece zaman ihtiyaç kullanmak getApplicationContext().

Açıkçası, bazı programcılar Java deneyimleri sınırlı olduğu için getApplicationContext()(veya getBaseContext()daha az oranda) kullanırlar. Bir iç sınıf uygularlar (örneğin, OnClickListenera Buttonin a an için Activity) ve a'ya ihtiyaç duyarlar Context. Aksine kullanmaktan daha MyActivity.thisdış sınıfında almak için this, kullandıkları getApplicationContext()veya getBaseContext()a almakContext nesneyi .

Sen sadece kullanmak getApplicationContext()ne zaman biliyor bir ihtiyaç Contextolasılıkla diğerlerinden daha uzun yaşamak olmayacak bir şey için Contextemrinde var. Senaryolar şunları içerir:

  • Kendisinin küresel bir kapsama sahip olacağı getApplicationContext()bir şeye ihtiyacınız varsa kullanın Context. Kullandığım getApplicationContext()içinde, örneğin, WakefulIntentServicestatik için, WakeLockhizmet için kullanılacak. Bu WakeLockstatik olduğundan ve oluşturmak Contextiçin almak PowerManageriçin bir gerekir, kullanmak en güvenlidir getApplicationContext().

  • Kullanım getApplicationContext()Bir bağlamak ne zaman Servicebir den Activitygeçmek istiyorsanız, ServiceConnection(yani bağlayıcı kolu) arasındaki Activityörneklerde yoluyla onRetainNonConfigurationInstance(). Android, bunlar aracılığıyla bağlamaları dahili olarak izler ve bağlamaları oluşturanlara ServiceConnectionsreferanslar tutar Contexts. 'Dan bağlanırsanız Activity, yeni Activityörneğin ServiceConnection, eski ile örtük bir referansı olan bir referansı olacaktır ve eski Activity, Activityçöp toplanamaz.

Bazı geliştiriciler Application, üzerinden aldıkları kendi global verileri için özel alt sınıfları kullanır getApplicationContext(). Bu kesinlikle mümkün. Statik veri üyelerini tercih ederim, eğer başka bir sebepten ötürü sadece bir özel Applicationnesneniz olabilir. Özel bir Applicationnesne kullanarak bir uygulama oluşturdum ve ağrılı olduğunu gördüm . Bayan Hackborn da bu görüşe katılıyor .

İşte nedenleri şunlardır değil kullanımına getApplicationContext()nereye giderseniz gidin:

  • Tamamen değil Context, her şeyi destekliyor Activity. Bununla yapmaya çalışacağınız çeşitli şeyler Contextbaşarısız olur, çoğunlukla GUI ile ilgilidir .

  • Eğer, hafıza sızıntılarını oluşturabilir Contextdan getApplicationContext()Üzerinde aramalar yarattığı şey üzerine tutan temiz up bilmediğimiz. Bir Activityşeyle tutarsa, Activityçöp toplandıktan sonra, diğer her şey de temizlenir. ApplicationNesnesi sürecinin ömrü boyunca kalır.


1
Bu cevap için çok teşekkür ederim. Bu yanıtı okumadan önce bulduğum başka bir bağlantı da bazı insanlara yardımcı olabilir. stackoverflow.com/questions/7298731/… - bu bağlantı bellek sızıntısıyla ilgili endişelerimi açıklıyor.
Norfeldt

27
@Norfeldt: FYI, yorumunuzdaki bağlantı bu cevaba geri dönüyor.
CommonsWare

2
teşekkür ederim .. bu bağlantıydı: stackoverflow.com/questions/5796611/… bunu kullanarak almaktan korktuğum bellek sızıntısını anlatıyor
Norfeldt

6
@djaqeel: Teklifinizin ikinci kısmı neredeyse doğrudur. "Statik veri üyesi gibi Faaliyet'ten daha uzun süre yaşayacak bir şeye Etkinlik bağlamı vermeyin" şeklinde daha iyi ifade edilir. Bununla birlikte, yine de sadece belirli bir durumda neden tam olarak ihtiyaç duyduğunuzu getApplicationContext()bildiğinizde kullanırsınız . Bir düzen şişirme? Etkinliği kullanın. Bir konfigürasyon değişikliğinden kurtulmak için bu bağlamaya ihtiyaç duyduğunuz bir hizmete mi bağlanıyorsunuz? Kullanın , böylece ciltleme örneğe bağlı değildir . getApplicationContext()Activity
CommonsWare

7
@Sever: Cevabımda bunu ele alıyorum. Dave Smith ayrıca bağlamları kapsayan mükemmel bir blog yayınına da sahiptir: doubleencore.com/2013/06/context Özet paragrafı: "Çoğu durumda, içinde çalıştığınız çevreleyen bileşenden doğrudan kullanabileceğiniz Bağlamı kullanın. bir referans, söz konusu bileşenin yaşam döngüsünün ötesine geçmediği sürece, bir faaliyetin veya Hizmetinizin ötesinde yaşayan bir nesneden bir Bağlama referansını geçici olarak kaydetmeniz gerektiğinde, kaydettiğiniz referansı değiştirin uygulama bağlamına geçelim. "
CommonsWare

48

Bence SDK sitesinde kötü belgelenmiş bir sürü şey var, bu onlardan biri. Yapacağım iddia, bir uygulama bağlamını varsayılan olarak kullanmanın ve yalnızca gerçekten ihtiyacınız olduğunda bir aktivite bağlamını kullanmanın daha iyi gibi görünmesi. Bir etkinlik bağlamına ihtiyacınız olduğunu gördüğüm tek yer bir ilerleme iletişim kutusu içindir. SBERG412, bir tost mesajı için bir etkinlik bağlamı kullanmanız gerektiğini iddia ediyor, ancak Android dokümanları, kullanılan bir uygulama bağlamını açıkça gösteriyor. Bu Google örneği nedeniyle her zaman tostlar için uygulama bağlamı kullandım. Bunu yapmak yanlışsa, Google topu buraya bıraktı.

Düşünmek ve gözden geçirmek için daha fazlası:

Bir tost mesajı için, Google Geliştirici Kılavuzu uygulama içeriğini kullanır ve açıkça şunu kullanır: belirtir Tost Bildirimleri

Geliştirici kılavuzunun iletişim kutuları bölümünde, bir AlertDialog.Builder uygulamasının uygulama bağlamını kullandığını ve ardından ilerleme çubuğunun bir etkinlik bağlamı kullandığını görürsünüz. Bu, Google tarafından açıklanmamıştır. İletişim Kutuları

Uygulama bağlamını kullanmanın iyi bir nedeni, bir yönlendirme değişikliği gibi yapılandırma değişikliklerini işlemek istediğiniz ve Görünümler gibi bir içeriğe ihtiyaç duyan nesneleri korumak istediğinizdir. Buraya bakarsanız: Çalışma Süresi Değişiklikleri Bir etkinlik içeriği kullanma konusunda sızıntı oluşturabilecek bir uyarı vardır. Bu, korunacak görüşlere sahip bir uygulama bağlamıyla önlenebilir (en azından benim anlayışım budur). Yazdığım bir uygulamada, bir uygulama bağlamı kullanmayı planlıyorum çünkü bir yönelim değişikliğindeki bazı görünümleri ve diğer şeyleri tutmaya çalışıyorum ve yine de aktivitenin yönlendirme değişikliklerinde yok olmasını ve yeniden oluşturulmasını istiyorum. Böylece (bkz bir bellek sızıntısına neden olmayan bir uygulama bağlamında kullanmak zorunda bellek sızıntısı önleme ). Bana göre, bir etkinlik bağlamı yerine uygulama bağlamını kullanmak için birçok iyi neden var gibi görünüyor ve bana göre neredeyse bir aktivite bağlamından daha sık kullanacaksınız gibi görünüyor. Yaşadığım birçok Android kitabının yaptığı şey bu ve gördüğüm Google örneklerinin çoğunun yaptığı da bu.

Google dokümantasyonu, uygulama bağlamının kullanılmasının çoğu durumda mükemmel derecede iyi görünmesini sağlar ve aslında örneklerinde bir etkinlik bağlamı kullanmaktan daha sık görülür (en azından gördüğüm örnekler). Uygulama bağlamını kullanmak gerçekten böyle bir sorunsa, Google'ın buna daha fazla önem vermesi gerekir. Açıklığa kavuşturmaları gerekiyor ve örneklerinden bazılarını tekrarlamaları gerekiyor. Yetki (Google) gerçekten uygulama bağlamlarını kullanmak bir sorun değil gibi görünmesini sağladığı için bunu tamamen deneyimsiz geliştiriciler için suçlamam.


5
Tamamen katılıyorum. CommonsWare cevabı bana biraz sürpriz oldu. Google dokümanlarında getApplicationContext kullanmanın çok tehlikeli olabileceğini düşündürdüğü için bu soruyu bulduğuma sevindim.
Steve Schwarcz

38

Bu tabloyu Uygulama bağlamı (ie:) getApplicationContext()ve etkinlik bağlamı , ayrıca BroadcastReceiver bağlamı gibi farklı Bağlam türlerinin ne zaman kullanılacağı için bir rehber olarak kullandım :

resim açıklamasını buraya girin

Daha fazla bilgi için tüm haklar burada orijinal yazara gider .


11

Hangi bağlam kullanılır?

İki tür Bağlam vardır:

  1. Uygulama bağlamı uygulama ile ilişkilidir ve uygulamanın ömrü boyunca her zaman aynı olacaktır - değişmez. Dolayısıyla, Tost kullanıyorsanız, uygulama içeriğini veya hatta etkinlik içeriğini (her ikisini de) kullanabilirsiniz, çünkü tost, uygulamanızdaki herhangi bir yerden görüntülenebilir ve belirli bir pencereye eklenmez. Ancak birçok istisna vardır, bir istisna, etkinlik bağlamını kullanmanız veya geçmeniz gerektiğidir.

  2. Etkinlik bağlamı , etkinlikle ilişkilendirilir ve etkinlik yok edilirse yok edilebilir - tek bir uygulamada birden fazla etkinlik (büyük olasılıkla daha fazla) olabilir. Ve bazen etkinlik bağlamı tutamağına kesinlikle ihtiyacınız vardır. Örneğin, yeni bir etkinlik başlattığınızda, yeni başlatma etkinliğinin etkinlik yığını açısından geçerli etkinliğe bağlanabilmesi için niyetinde etkinlik bağlamını kullanmanız gerekir. Ancak, yeni bir etkinlik başlatmak için uygulamanın bağlamını da kullanabilirsiniz, ancak daha sonra Intent.FLAG_ACTIVITY_NEW_TASKyeni bir görev olarak değerlendirmek amacıyla bayrağı ayarlamanız gerekir .

Bazı vakaları ele alalım:

  • MainActivity.this Etkinlik sınıfını genişleten MainActivity bağlamını belirtir, ancak temel sınıf (etkinlik) de Context sınıfını genişletir, böylece etkinlik bağlamı sunmak için kullanılabilir.

  • getBaseContext() etkinlik bağlamı sunar.

  • getApplication() uygulama bağlamı sunar.

  • getApplicationContext() ayrıca uygulama bağlamı sunar.

Daha fazla bilgi için lütfen bu bağlantıyı kontrol edin .


Uygulamada bir AlertDialog görüntülenmesi gerektiğinde, örneğin bir sonucu gösteren bir zaman uyumsuz işlem ne durumda? Bunun bir örneği şunlar olabilir : kullanıcı indirmeyi tıklar, bu bir indirme isteği downloadmanagerbaşlatır ve bitmiş sinyal alındığında, bir iletişim kutusu göstermelidir, örneğin "Bu indirme ile ne yapmak istersiniz?". Benim (hack) çözümüm Activitybir static Applicationsınıftaki en son kayıtları kaydeder Activityve indirme tamamlandığında geçerli olanı ister. Ancak, bunun doğru bir uygulama olduğundan şüpheliyim. TL; DR AlertDialog'u uygulamanın herhangi bir yerinde nasıl görüntüleyebilirim?
CybeX

@KGCybeX İndirme tamamlandığında uygulamanızda herhangi bir yerde herhangi bir şey görüntülemek istiyorsanız, indirme hizmetinizin yayınlayacağı belirli bir mesajı dinleyen ve ekledikten sonra istediğiniz her şeyi yapan aktivitenize manuel olarak bir yayın alıcısı kaydettirmelisiniz. doğrudan bu hizmete olan etkinliğiniz.
ExiRouS

6

Neden desteklediği her işlem için Uygulama Bağlamı kullanmama merak ediyordum. Sonunda getContext () veya getActivity () için bellek sızıntısı ve eksik null kontrolünü azaltır. Bayan Hackborn'un Uygulama Bağlamını yalnızca gerekirse kullanması gibi ifadeler, neden bir açıklama yapmadan benim için ikna edici görünmüyor. Ama öyle görünmüyor ki neden bir çirkinlik var:

bazı Android sürümü / cihaz kombinasyonlarında bu kurallara uymayan sorunlar olduğunu bulduk. Örneğin, bir Bağlam geçirilen bir BroadcastReceiver'ım varsa ve bu Bağlamı bir Uygulama Bağlamına dönüştürdüğümde ve ardından Uygulama Bağlamında registerReceiver () öğesini çağırmayı denediğimde, bunun iyi çalıştığı birçok örnek var, ancak aldığım birçok örnek var. ReceiverCallNotAllowedException nedeniyle çökme. Bu çökmeler API 15'ten 22'ye kadar çok çeşitli Android sürümlerinde meydana gelir. Https://possiblemobile.com/2013/06/context/#comment-2443283153

Aşağıdaki tabloda Uygulama Bağlamı tarafından desteklendiği şekilde açıklanan tüm işlemlerin tüm Android cihazlarda çalışacağı garanti edilmez! resim açıklamasını buraya girin


4

Uygulama bağlamına karşı Etkinlik bağlamını ne zaman kullanmanız gerektiğine dair iki harika örnek, Uygulama bağlamını kullanmak bir istisnaya neden olacağından bir Tost mesajı veya yerleşik bir İletişim Kutusu mesajı görüntülerken gösterilebilir:

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

veya

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

Bunların her ikisi de Uygulama bağlamında sağlanmayan Etkinlik bağlamından bilgiye ihtiyaç duyar.


5
Hm .. Hangi Android işletim sistemi sürümünü test ettiniz? 4.4.4 üzerinde test yaptım ve iyi çalışıyor. Ayrıca, @Andi Jay'in belirttiği gibi, resmi Android geliştirici belgesi, örnek kodlarında uygulama bağlamını kullandı. developer.android.com/guide/topics/ui/notifiers/…
김준호

1
@Çin adı, evet işe yarayabilir, ancak bazen bu uygulamanın geleceğinde, aynı zamanda çökecektir. Bana birkaç kez başvurdu.
Ojonugwa Jude Ochalifu

1
Toast'ta Etkinlik bağlamını kullandığımda bellek sızdırıyor!
Jemshit Iskenderov

3

Uygulamanız yalnızca canlı oluncaya kadar uygulama içeriği canlıdır ve Etkinlik Yaşam Döngüsüne bağlı değildir, ancak bağlam nesnesini uzun ömürlü tutar . Geçici olarak kullandığınız nesne, o zaman Uygulama Bağlamını ve Etkinlik Bağlamını kullanın Uygulama Bağlamının tamamen açıklığı olarak kullanılır.

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.