Bağlam olarak getApplication () ile "Pencere eklenemiyor - simge null bir uygulama için değil" iletişim kutusu


665

Etkinliğim, parametre olarak bir Bağlam gerektiren bir AlertDialog oluşturmaya çalışıyor. Ben kullanırsanız bu beklendiği gibi çalışır:

AlertDialog.Builder builder = new AlertDialog.Builder(this);

Ancak, bir ekran döndürme gibi basit bir şey sırasında bile Etkinlik yok edildiğinde ve yeniden oluşturulduğunda bellek sızıntısı potansiyeli nedeniyle "bunu" bir bağlam olarak kullanmaktan keyif duyuyorum. Android geliştiricisinin blogundaki ilgili bir gönderiden :

Bağlama bağlı bellek sızıntılarını önlemenin iki kolay yolu vardır. En bariz olanı, bağlamın kendi kapsamının dışına çıkmasından kaçınmaktır. Yukarıdaki örnek statik bir referansı gösterdi ancak iç sınıflar ve bunların dış sınıfa dolaylı referansları aynı derecede tehlikeli olabilir. İkinci çözüm Uygulama bağlamını kullanmaktır. Bu bağlam, uygulamanız canlı olduğu ve etkinliklerin yaşam döngüsüne bağlı olmadığı sürece yaşayacaktır. Bağlama ihtiyacı olan uzun ömürlü nesneleri tutmayı planlıyorsanız, uygulama nesnesini unutmayın. Context.getApplicationContext () veya Activity.getApplication () öğesini çağırarak kolayca edinebilirsiniz.

Ama için AlertDialog()ne getApplicationContext()ya getApplication()da istisna atar gibi bir Bağlamında olarak kabul edilebilir:

"Pencere eklenemedi - simge null bir uygulama için değil"

referans başına: 1 , 2 , 3 vb.

Yani, resmen kullanmamız önerildiğinden Activity.getApplication()ve reklamı yapılmadığı için bu gerçekten bir "böcek" olarak düşünülmeli mi?

Jim


R.Guy'un getApplication kullanmanızı önerdiği ilk öğe için referans: android-developers.blogspot.com/2009/01/…
gymshoe 26:11




Yanıtlar:


1354

Bunun yerine getApplicationContext(), sadece kullanın ActivityName.this.


67
Harika! Sadece bunun hakkında yorum yapmak için .. bazen "bu" kelimesini, "dinleyenin" bu "özelliğine sahip bir dinleyicinin uyguladığı yönteminde erişmek için küresel olarak (örneğin) depolamanız gerekebilir. Bu durumda, genel olarak "Bağlam bağlamı" tanımlayın ve sonra onCreate'de "context = this" ayarlayın ve sonra "bağlam" a bakın. Umarım bu da işe yarar.
Steven L

8
Aslında, Listenersınıflar genellikle anonim-iç olduğu için, sadece yapma eğilimindeyim final Context ctx = this;ve uzaktayım;)
Alex

28
@StevenL Söylediklerinizi yapmak için, ExternalClassName.this komutunu kullanarak dış sınıfın "this" ifadesine açıkça başvurmalısınız.
Artem Russakovskii

11
Diyalog pencereniz geri aramada kullanılıyorsa ve geri arama çağrılmadan önce etkinlikten ayrılırsanız "bu" ifadeyi kullanmaz mısınız? En azından Android'in logcat'te şikayet ettiği şey bu.
Artem Russakovskii

6
@StevenLs yaklaşımını tavsiye etmem, çünkü onDestroy - Artem'deki statik referansı temizlemeyi hatırlamadığınız sürece bu etkinliğin belleğini kolayca sızdırabilirsiniz. StevenLs yaklaşımı Java'nın nasıl çalıştığını anlama eksikliğinden kaynaklanmaktadır
Dori

192

Kullanmak thisbenim için işe yaramadı, ama işe MyActivityName.thisyaradı. Umarım bu thisişe alamayan herkese yardımcı olur .


63
thisBir iç sınıfın içinden kullandığınızda olan şey budur . Bir dış sınıf örneğine başvurmak istiyorsanız, bunu yaptığınız gibi belirtmeniz gerekir OuterClass.this. Sadece thisher zaman en iç sınıf örneğine başvurmak.
kaka

60

Kullanmaya devam edebilirsiniz getApplicationContext(), ancak kullanmadan önce şu bayrağı eklemeniz gerekir:, dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)ve hata gösterilmez.

Manifestinize aşağıdaki izni ekleyin:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

1
Pencere eklenemedi android.view.ViewRootImpl$W@426ce670 - Bu pencere türü için izin reddedildi
Ram G.

izin ekle: <kullanımları izin android: name = "android.permission.SYSTEM_ALERT_WINDOW" />
codezjx

3
API 23'ten itibaren bu izni etkinleştiremeyeceğiniz anlaşılıyor. Code.google.com/p/android-developer-preview/issues/…
roy zhang

1
API 23'ten sonra kullanabilirsiniz, ancak kullanıcıyı istemeniz gerekir: startActivityForResult (yeni Niyet (Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse ("package:" + getPackageName ())), OVERLAY_PERMISSION_REQ_CODE); ancak, ister gerektiğini kullanmak o başka bir konu ... olduğunu
Ben Neill

2
Hizmet içinde ilerleme durumu iletişim kutusu görüntülendiğinde yararlıdır
Anand Savjani

37

"... AlertDialog () için ne getApplicationContext () ne de getApplication () için bir istisna attığından bir Bağlam olarak kabul edilemez dediğinde sorunu doğru bir şekilde belirlediniz: 'Pencere eklenemiyor - simge null değil bir uygulama'"

Bir İletişim Kutusu oluşturmak için, Uygulama Bağlamına değil, hem GetApplicationContext () hem de getApplication () öğelerinin bir Uygulama Bağlamı döndürmesine değil, bir Etkinlik Bağlamına veya Hizmet Bağlamına ihtiyacınız vardır .

Etkinlik Bağlamını şu şekilde elde edebilirsiniz :

(1) Bir Faaliyette veya Hizmette:

AlertDialog.Builder builder = new AlertDialog.Builder(this);

(2) Bir Fragmanda: AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

Bellek sızıntıları, bir nesnenin kendisine referansı olan "bu" referansına özgü bir problem değildir (yani, nesnenin verilerini depolamak için tahsis edilen gerçek hafızaya referans). Ayrılan bellek yararlı ömrünü geçtikten sonra Çöp Toplayıcısının (GC) boşaltamayacağı herhangi bir ayrılmış bellekte olur .

Çoğu zaman, bir değişken kapsam dışına çıktığında, bellek GC tarafından geri kazanılır. Ancak, "x" gibi bir değişken tarafından tutulan bir nesneye yapılan başvuru, nesne yararlı ömrünü geçtikten sonra bile devam ettiğinde bellek sızıntıları meydana gelebilir. GC çünkü ayrılan bellek dolayısıyla sürece "x" bir referansı tutar olarak kayıp olacak olmayacak o hafıza hala başvuruluyor uzun olduğunca için bellek boşaltmak. Bazen, ayrılan belleğe bir referans zinciri nedeniyle bellek sızıntıları görülmez . Böyle bir durumda, GC o belleğe yapılan tüm referanslar kaldırılıncaya kadar belleği boşaltmaz.

Bellek sızıntılarını önlemek için, ayrılan belleğe "this" (veya diğer başvurular) tarafından süresiz olarak başvurulmasına neden olan mantıksal hatalar için kodunuzu kontrol edin. Zincir referanslarını da kontrol etmeyi unutmayın. Bellek kullanımını analiz etmenize ve bu sinir bozucu bellek sızıntılarını bulmanıza yardımcı olmak için kullanabileceğiniz bazı araçlar şunlardır:


Bir Etkinlik İçin de kullanabilirsiniz ActivityName.this nerede ActivityName (örneğin MainActivity için) (besbelli) sizin etkinliğin adıdır
Luis Cabrera Benito

34

Diyalog pencereniz "bağlam gerektiren uzun ömürlü bir nesne" olmamalıdır. Belgeler kafa karıştırıcı. Temel olarak şöyle bir şey yaparsanız:

static Dialog sDialog;

( statik değerine dikkat edin )

Sonra bir yerdeki bir aktivitede

 sDialog = new Dialog(this);

Etkinliği yok edecek bir rotasyon veya benzeri bir şey sırasında orijinal etkinliği sızdırıyor olabilirsiniz. (OnDestroy'da temizlemediğiniz sürece, ancak bu durumda muhtemelen Dialog nesnesini statik yapmazsınız)

Bazı veri yapıları için, bunları statik hale getirmek ve uygulamanın bağlamını temel almak mantıklı olacaktır, ancak genellikle iletişim kutuları gibi kullanıcı arayüzüyle ilgili şeyler için geçerli değildir. Yani böyle bir şey:

Dialog mDialog;

...

mDialog = new Dialog(this);

İyi ve mDialog statik olmadığı için aktivite ile serbest bırakılacağı için aktiviteyi sızdırmamalıdır.


ben bir asynctask deniyorum, bu benim için çalıştı, thx dostum
MemLeak

benim iletişim statik oldu, bir kez çalıştı statik bildirimi kaldırıldı.
Ceddy Muhoza

25

Bağlamımı bir parçada görüntülenen özel bir bağdaştırıcı üzerinde bir kurucu aracılığıyla göndermek zorunda kaldı ve getApplicationContext () ile bu sorunu vardı. Ben çözdüm:

this.getActivity().getWindow().getContext()parçaların onCreategeri çağrısında.


4
Bu benim için de çalıştı, kullandığım harici AsyncTask'ın yapıcısına geçtim (Bir ilerleme iletişim kutusu gösterir).
Rohan Kandwal

3
Bu daha karmaşık görevler için GERÇEK cevap :)
teejay

1
@Teejay'e katılıyorum
Erdi İzgi

23

içinde Faaliyet sadece kullanın:

MyActivity.this

içinde Parçası:

getActivity();

Bu benim Etkinliğimde benim için düzeltti. Teşekkürler
Werner

20

Gelen Activitybir iletişim kutusu gösteren düğmeye tıklayın

Dialog dialog = new Dialog(MyActivity.this);

Benim için çalıştı.


19

***** kotlin sürümü *****

Sen geçmelidir this@YourActivityyerine applicationContextveyabaseContext


18

Küçük kesmek: Eğer GC ile etkinlik yok önleyebilir (bunu yapmamalı, ancak bazı durumlarda yardımcı olabilir setine unutmayın. contextForDialogİçin nullartık ihtiyaç duyulduğunda):

public class PostActivity extends Activity  {
    ...
    private Context contextForDialog = null;
    ...
    public void onCreate(Bundle savedInstanceState) {
        ...
        contextForDialog = this;
    }
    ...
    private void showAnimatedDialog() {
        mSpinner = new Dialog(contextForDialog);
        mSpinner.setContentView(new MySpinner(contextForDialog));
        mSpinner.show();
    }
    ...
}

@MurtuzaKabul Çalışır, çünkü bu == Etkinlikten miras kalan Etkinlik -> Bağlamdan miras alır, bu yüzden iletişim kutusunu geçtiğinizde aslında aktiviteyi geçersiniz
Elad Gelman

13

Bir parça kullanıyorsanız ve AlertDialog / Toast mesajı kullanıyorsanız, context parametresinde getActivity () öğesini kullanın.

bunun gibi

ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();

12

Sadece aşağıdakileri kullanın:

JAVA KULLANICILARI İÇİN

Etkinlik kullanıyorsanız -> AlertDialog.Builder builder = new AlertDialog.Builder(this);

VEYA

AlertDialog.Builder builder = new AlertDialog.Builder(your_activity.this);

Eğer parça kullanıyorsanız -> AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

KOTLIN KULLANICILARI İÇİN

Etkinlik kullanıyorsanız -> val builder = AlertDialog.Builder(this)

VEYA

val builder = AlertDialog.Builder(this@your_activity.this)

Eğer parça kullanıyorsanız -> val builder = AlertDialog.Builder(activity!!)


9

ekleme

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

ve

"android.permission.SYSTEM_ALERT_WINDOW"/> açıkça

Şimdi benim için çalışıyor. Hatta uygulamayı kapatıp açtıktan sonra, o zaman bana hata verdi.


9

ProgressDialogBir parça kullanıyordum getActivity().getApplicationContext()ve yapıcı parametresi olarak geçerken bu hatayı alıyordum . Bunu değiştirmek de getActivity().getBaseContext()işe yaramadı.

Benim için işe yarayan çözüm geçmekti getActivity(); yani

progressDialog = new ProgressDialog(getActivity());


6

kullanım MyDialog md = new MyDialog(MyActivity.this.getParent());


6

Etkinlik dışındaysanız, Etkinlik etkinliği olarak "NameOfMyActivity.this" işlevinizi kullanmanız gerekir, örnek:

public static void showDialog(Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("Your Message")
        .setPositiveButton("Yes", dialogClickListener)
        .setNegativeButton("No", dialogClickListener).show();
}


//Outside your Activity
showDialog(NameOfMyActivity.this);

5

Bir parça kullanıyorsanız ve bir AlertDialog / Toastmesaj kullanıyorsanız getActivity(), context parametresinde kullanın .

Benim için çalıştı.

Şerefe!


5

İletişim kutusunun altında olacak bir etkinliğin içeriğini kullanmaya çalışın. Ancak "bu" anahtar kelimeyi kullanırken dikkatli olun, çünkü her seferinde işe yaramaz.

Örneğin, TabActivity'yi iki sekmeli ana bilgisayar olarak kullanıyorsanız ve her sekme başka bir etkinlikse ve sekmelerden (etkinlikler) birinden iletişim kutusu oluşturmaya çalışırsanız ve "this" kullanırsanız, istisna elde edersiniz. büyük / küçük harf iletişim kutusu, her şeyi barındıran ve görünür olan ana bilgisayar etkinliğine bağlanmalıdır. (en görünür üst Etkinliğin bağlamını söyleyebilirsiniz)

Bu bilgiyi herhangi bir belgeden bulamadım ama deneyerek. Bu benim güçlü arka plan olmadan benim çözüm, daha iyi bilinen bir kimse varsa, yorum yapmaktan çekinmeyin.


4

Gelecekteki okuyucular için bu yardımcı olacaktır:

public void show() {
    if(mContext instanceof Activity) {
        Activity activity = (Activity) mContext;
        if (!activity.isFinishing() && !activity.isDestroyed()) {
            dialog.show();
        }
    }
}


2

Ya da başka bir olasılık Dialog'u aşağıdaki gibi oluşturmaktır:

final Dialog dialog = new Dialog(new ContextThemeWrapper(
            this, R.style.MyThemeDialog));

2

Ana UI iş parçacığı olmayan bir iş parçacığından bir iletişim kutusu göstermeye çalışıyorsanız da olabileceğini düşünüyorum.

runOnUiThread()Bu durumda kullanın .


2

getParent()Yeni AlertDialog.Builder(getParent());Umut işe yarayacak gibi bağlamın argüman yerinde deneyin , benim için çalıştı.


1

API'ye bir göz attıktan sonra, iletişim kutusundaki etkinliğinizi iletebilir veya bir parçadaysanız getActivity'yi, ardından sızıntıları önlemek için dönüş yöntemlerinde dialog.dismiss () ile kuvvetlice temizleyebilirsiniz.

Açıkça bildiğim her yerde belirtilmemiş olsa da, sadece bunu yapmak için OnClickHandlers iletişim kutusunu geri geçirilmiş gibi görünüyor.


0

İletişim Kutunuz bağdaştırıcıda oluşturuluyorsa:

Etkinliği Adaptör Yapıcısına Aktarın:

adapter = new MyAdapter(getActivity(),data);

Adaptörden Alın:

 public MyAdapter(Activity activity, List<Data> dataList){
       this.activity = activity;
    }

Artık Builder'ınızda kullanabilirsiniz

            AlertDialog.Builder alert = new AlertDialog.Builder(activity);

-1

Uygulamam için aynı hatayı
şu şekilde çözdüm: İletişim kutusunu oluşturduktan sonra aşağıdaki satırı ekleme:

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  

Bir bağlam edinmeniz gerekmeyecek. Bu, özellikle mevcut açılan iletişim kutusundan başka bir iletişim kutusu açıyorsanız yararlıdır. Veya bir bağlam elde etmek uygun olmadığında.

Bu uygulama geliştirme ile size yardımcı olabilir umuyoruz.

David


-1
android.support.v7.app.AlertDialog.Builder builder = new android.support.v7.app.AlertDialog.Builder(getWindow().getDecorView().getRootView().getContext());

builder.setTitle("Confirm");
builder.setMessage("Are you sure you want delete your old account?");

builder.setPositiveButton("YES", new DialogInterface.OnClickListener() {

    public void onClick(DialogInterface dialog, int which) {
        //Do nothing but close the dialog



        dialog.dismiss();

    }
});

builder.setNegativeButton("NO", new DialogInterface.OnClickListener() {

    @Override
    public void onClick(DialogInterface dialog, int which) {

        //Do nothing
        dialog.dismiss();
    }
});

android.support.v7.app.AlertDialog alert = builder.create();
alert.show();
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.