Buider.show () üzerinde “android.view.WindowManager $ BadTokenException: Pencere eklenemiyor”


120

Ana bölümümden activity, bir iç sınıfı çağırmam gerekiyor ve sınıf içindeki bir yöntemde göstermem gerekiyor AlertDialog. Kapattıktan sonra, Tamam düğmesine basıldığında, satın almak için Google Play'e iletin.

İşler çoğu zaman mükemmel çalışıyor, ancak birkaç kullanıcı için kilitleniyor builder.show()ve "android.view.WindowManager$BadTokenException:kilitlenme günlüğünden pencere eklenemiyor "ifadesini görebiliyorum . Lütfen önerin.

Kodum hemen hemen şuna benzer:

public class classname1 extends Activity{

  public void onCreate(Bundle savedInstanceState) {
    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.<view>); 

    //call the <className1> class to execute
  }

  private class classNamename2 extends AsyncTask<String, Void, String>{

    protected String doInBackground(String... params) {}

    protected void onPostExecute(String result){
      if(page.contains("error")) 
      {
        AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
        builder.setCancelable(true);
        builder.setMessage("");
        builder.setInverseBackgroundForced(true);
        builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int whichButton){
            dialog.dismiss();
            if(!<condition>)
            {
              try
              {
                String pl = ""; 

                mHelper.<flow>(<class>.this, SKU, RC_REQUEST, 
                  <listener>, pl);
              }

              catch(Exception e)
              {
                e.printStackTrace();
              }
            }  
          }
        });

        builder.show();
      }
    }
  }
}

Hatayı başka bir uyarıya iletmediğim başka bir uyarıda da gördüm activity. Bunun gibi basit:

AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
    builder.setCancelable(true);

    //if successful
    builder.setMessage(" ");
    builder.setInverseBackgroundForced(true);
    builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton){
            // dialog.dismiss();
                   }
    });
    builder.show();
}

2
Tam kodunuz buysa, AsyncTask'a gerçekten ihtiyacınız var mı?
Shobhit Puri

Bu kodun tamamı değil, bu oldukça büyük bir kod, bu yüzden buraya yalnızca çökme raporundan sorun gördüğüm kısmı ekledim
MSIslam

tamam iyi. Genellikle sadece işlev adını gönderebilir ve orada bir sürü şey yaptığınıza dair yorum yapabilirsiniz (şimdi yaptığınız gibi). Anlaması daha kolay. :).
Shobhit Puri

Bir yerde bu aktiviteden başka bir aktiviteye mi gidiyorsunuz?
Shobhit Puri

1
Yazdığınız yorumlardır //send to some other activity. Sanırım yeni bir Aktiviteye gideceğiniz kısım hakkında yorum yaparsanız bu hata ortadan kalkacaktır. Hata, önceki iletişiminiz tamamen kapatıldığı ve yeni etkinliğiniz başladığından kaynaklanıyor gibi görünüyor. İçinde, onPostExecute()uyarı diyaloğuna sahipsiniz ve loginFaaliyetin bağlamını veriyorsunuz . Ancak diğer aktiviteye gidersiniz, bu nedenle bağlam yanlış olur. Dolayısıyla bu hatayı alıyorsunuz! Stackoverflow.com/questions/15104677/… benzer soruya bakın .
Shobhit Puri

Yanıtlar:


266
android.view.WindowManager$BadTokenException: Unable to add window"

Sorun :

Bu istisna, uygulama kullanıcıyı bir İletişim Kutusu açarak arka plan iş parçacığından (AsyncTask) bilgilendirmeye çalışırken oluşur.

Kullanıcı arayüzünü arka plan iş parçacığından (genellikle AsyncTask'ın onPostExecute () öğesinden) değiştirmeye çalışıyorsanız ve etkinlik bitiş aşamasına girerse) açıkça finish () çağırarak, kullanıcının home veya back düğmesine basması veya Android tarafından yapılan etkinlik temizlemesi bu hatayı al.

Nedeni:

Bu istisnanın nedeni, istisna mesajının da belirttiği gibi, faaliyetin bitmiş olması, ancak bitmiş faaliyetin bağlamını içeren bir iletişim kutusu görüntülemeye çalışmanızdır. İletişim kutusunun görüntüleneceği pencere olmadığından, android çalışma zamanı bu istisnayı atar.

Çözüm:

isFinishing()Bu etkinliğin bitirme sürecinde olup olmadığını kontrol etmek için Android tarafından çağrılan yöntemi kullanın : ister açık finish () çağrısı ister Android tarafından yapılan etkinlik temizleme olsun. Bu yöntemi kullanarak, etkinlik tamamlanırken arka plan iş parçacığından iletişim kutusunu açmaktan kaçınmak çok kolaydır.

Ayrıca weak referenceaktivite için bir de bulundurun (ve aktivitenin ihtiyaç duyulmadığında yok edilebilmesi için güçlü bir referans olmayın) ve bu aktivite referansını kullanarak herhangi bir UI gerçekleştirmeden önce (yani bir diyalog göstererek) aktivitenin bitip bitmediğini kontrol edin.

ör .

private class chkSubscription extends AsyncTask<String, Void, String>{

  private final WeakReference<login> loginActivityWeakRef;

  public chkSubscription (login loginActivity) {
    super();
    this.loginActivityWeakRef= new WeakReference<login >(loginActivity)
  }

  protected String doInBackground(String... params) {
    //web service call
  }

  protected void onPostExecute(String result) {
    if(page.contains("error")) //when not subscribed
    {
      if (loginActivityWeakRef.get() != null && !loginActivityWeakRef.get().isFinishing()) {
        AlertDialog.Builder builder = new AlertDialog.Builder(login.this);
        builder.setCancelable(true);
        builder.setMessage(sucObject);
        builder.setInverseBackgroundForced(true);

        builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int whichButton){
            dialog.dismiss();
          }
        });

        builder.show();
      }
    }
  }
}

Güncelleme :

Pencere Jetonları:

Adından da anlaşılacağı gibi, pencere simgesi, pencere yöneticisinin sistemdeki bir pencereyi benzersiz şekilde tanımlamak için kullandığı özel bir Bağlayıcı simgesi türüdür. Pencere belirteçleri, kötü amaçlı uygulamaların diğer uygulamaların pencerelerinin üzerine çizim yapmasını imkansız kıldığından güvenlik açısından önemlidir. Pencere yöneticisi, her bir pencere ekleme veya kaldırma isteğinin bir parçası olarak uygulamaların pencere belirtecini iletmelerini zorunlu kılarak buna karşı koruma sağlar. Belirteçler eşleşmezse, pencere yöneticisi isteği reddeder ve bir BadTokenException oluşturur . Pencere simgeleri olmadan, bu gerekli tanımlama adımı mümkün olmazdı ve pencere yöneticisi kendisini kötü amaçlı uygulamalardan koruyamazdı.

 Gerçek dünya senaryosu:

Bir uygulama ilk kez başlatıldığında,  ActivityManagerService  , uygulamanın en üst düzey kapsayıcı penceresini benzersiz şekilde tanımlayan, uygulama pencere simgesi adı verilen özel bir pencere simgesi oluşturur. Etkinlik yöneticisi bu belirteci hem uygulamaya hem de pencere yöneticisine verir ve uygulama, ekrana yeni bir pencere eklemek istediği her seferde belirteci pencere yöneticisine gönderir. Bu, uygulama ile pencere yöneticisi arasında güvenli etkileşim sağlar (diğer uygulamaların üzerine pencere eklemeyi imkansız kılar) ve ayrıca etkinlik yöneticisinin pencere yöneticisine doğrudan istekte bulunmasını kolaylaştırır.


Bu çok mantıklı! Ayrıca çözümünüz bana harika geliyor. (y)
MSIslam

'Boş son alan loginActivityWeakRef başlatılmamış olabilir' mesajı şu şekilde denendi: özel son WeakReference <login> loginActivityWeakRef = new WeakReference <login> (login.this); yapılacak doğru şey olup olmadığından emin değilim
MSIslam

Ayrıca WeakReference <login> loginActivityWeakRef'ten önceki finali yapıcıda hata gösterdiği için kaldırdım.
MSIslam

1
yeni chkCubscription (bu) .execute ("") kullanmayı deneyin; new chkCubscription.execute ("") yerine; yukarıda yayınladığınız gibi.
Ritesh Gune

2
Korkunç hata !! Bir öğreticiyi takip ediyorum ve @PhilRoggenbuck olarak, sorunum StartActivity (...) çağrılmadan hemen önce bir Toast..Show () çağırmaktan kaynaklanıyordu. Bunu düzeltmek için, tostu yeni çağrılan aktivitede taşıdım!
Thierry

27

Fonksiyonu gösteren diyalog vardı:

void showDialog(){
    new AlertDialog.Builder(MyActivity.this)
    ...
    .show();
}

Bu hatayı alıyordum ve isFinishing()bu iletişim kutusunu gösteren işlevi çağırmadan önce kontrol etmem gerekiyordu .

if(!isFinishing())
    showDialog();

1
yazmamalı mıyız if(!MyActivity.this.isFinishing())? MyActivity'de doğru değilse
Bibaswann Bandyopadhyay'de

2
Android zaten bitiyorsa neden herhangi bir kod çalıştırsın? Bu çözümü izlersek, benzer sorunları önlemek için isFinishing'i gerçekten kaç kez kullanmamız gerektiğini bir düşünün.
David

@David Bunun arka planda çağrılan diyalog gibi birkaç detayın eksik olduğunu düşünüyorum, ancak şu anki fikrinize tamamen katılıyorum.
Terk Edilmiş Sepet

Harika bir nokta, niçin kontrol etmem gerekiyor ki isFinishing!
Chibueze Opata

9

Olası neden, uyarı iletişim kutusunun içeriğidir. Bu aktiviteyi bitirmiş olabilirsiniz, bu nedenle bu bağlamda açılmaya çalışıyor, ancak bu zaten kapalı. O iletişim kutusunun bağlamını ilk etkinliğinize göre değiştirmeyi deneyin, çünkü sonuna kadar bitmeyecek.

Örneğin

bunun yerine.

AlertDialog alertDialog = new AlertDialog.Builder(this).create();

kullanmaya çalışmak

AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();

3
  • ilk olarak, doInBackground'u geçersiz kılmadan AsyncTask'ı genişletemezsiniz
  • ikinci olarak oluşturucudan AlterDailog oluşturmayı deneyin ve sonra show () 'u çağırın.

    private boolean visible = false;
    class chkSubscription extends AsyncTask<String, Void, String>
    {
    
        protected void onPostExecute(String result)
        {
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
            builder.setCancelable(true);
            builder.setMessage(sucObject);
            builder.setInverseBackgroundForced(true);
            builder.setNeutralButton("Ok", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int whichButton)
                {
                    dialog.dismiss();
                }
            });
    
            AlertDialog myAlertDialog = builder.create();
            if(visible) myAlertDialog.show();
        }
    
        @Override
        protected String doInBackground(String... arg0)
        {
            // TODO Auto-generated method stub
            return null;
        }
    }
    
    
    @Override
    protected void onResume()
    {
        // TODO Auto-generated method stub
        super.onResume();
        visible = true;
    }
    
    @Override
    protected void onStop()
    {
        visible = false; 
        super.onStop();
    }

1
Cevap için teşekkürler. Aslında doInBackground yöntemini kullandım, sadece uyarı ile ilgili olmadığı için burada bahsetmedim. Builder.create () işlevinin eklenmesi ile ilgili olarak iyi çalışıyor gibi görünüyor, ancak herkes için iyi çalışıp çalışmayacağını bilmiyorum. II'nin daha önce söylediği gibi, şu anki kodum da iyi çalışıyor, ancak birkaç kullanıcı için yalnızca birkaç kez pencere eklenemediğini gösteriyor. Lütfen bana kodlamamda buna neyin neden olabilecek asıl problem olabileceğini önerebilir misiniz?
MSIslam

bu durumda kullanıcı, onPostExecute çağrılmadan önce etkinliğinizden çıkar, bu nedenle iletişim kutusunu tutacak bir pencere yoktur ve bu, uygulamanızın çökmesine neden olur. Etkinliğinizin artık görünür olup olmadığını öğrenmek için onStop'a bayrak ekleyin ve ardından iletişim kutusunu göstermeyin.
moh.sukhni

doInBackground () 'dan gelen web hizmeti çağrısı sonucuna göre kullanıcının abone olup olmadığını kontrol ettiğimde builder.show () bir koşul altında olduğundan onPostExecute aslında çağrılıyor. Dolayısıyla, onPostExecute çağrılmasaydı, builder.show () satırına gelmezdi.
MSIslam

doInBackground'dan sonra varsayılan olarak onPostExecute çağrılır, onu çağıramazsınız ve orada ne olursa olsun çalıştırılır.
moh.sukhni

1
zaman uyumsuz göreviniz, kullanıcı etkinliğinizden çıktıktan sonra çalışmaya devam edecek ve bu, builder.show () 'un uygulamanızı çökertmesine neden olacaktır, çünkü sizin için kullanıcı arabirimini işleyecek bir etkinlik yoktur. bu nedenle uygulamanız web'den veri çekiyor, ancak siz verileri almadan önce etkinliğiniz yok edildi.
moh.sukhni

1

Ben İletişim Kutusu'na oluşturma onCreateve bunu kullanarak showve hide. Benim için temel neden, faaliyeti onBackPressedbitiren göz ardı etmek değildi Home.

@Override
public void onBackPressed() {
new AlertDialog.Builder(this)
                .setTitle("Really Exit?")
                .setMessage("Are you sure you want to exit?")
                .setNegativeButton(android.R.string.no, null)
                .setPositiveButton(android.R.string.yes,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                Home.this.finish();
                                return;
                            }
                        }).create().show();

onBackPressedDiyaloglarımı kapatmadan / kapatmadan Ev Aktivitesini bitiriyordum .

Diyaloglarımı kapattığımda çökme kayboldu.

new AlertDialog.Builder(this)
                .setTitle("Really Exit?")
                .setMessage("Are you sure you want to exit?")
                .setNegativeButton(android.R.string.no, null)
                .setPositiveButton(android.R.string.yes,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                networkErrorDialog.dismiss() ;
                                homeLocationErrorDialog.dismiss() ;
                                currentLocationErrorDialog.dismiss() ;
                                Home.this.finish();
                                return;
                            }
                        }).create().show();

0

Bunu çözmeyi denedim.

 AlertDialog.Builder builder = new AlertDialog.Builder(
                   this);
            builder.setCancelable(true);
            builder.setTitle("Opss!!");

            builder.setMessage("You Don't have anough coins to withdraw. ");
            builder.setMessage("Please read the Withdraw rules.");
            builder.setInverseBackgroundForced(true);
            builder.setPositiveButton("OK",
                    (dialog, which) -> dialog.dismiss());
            builder.create().show();

-1

Bunu dene :

    public class <class> extends Activity{

    private AlertDialog.Builder builder;

    public void onCreate(Bundle savedInstanceState) {
                    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
                    super.onCreate(savedInstanceState);

                setContentView(R.layout.<view>); 

                builder = new AlertDialog.Builder(<class>.this);
                builder.setCancelable(true);
                builder.setMessage(<message>);
                builder.setInverseBackgroundForced(true);

        //call the <className> class to execute
}

    private class <className> extends AsyncTask<String, Void, String>{

    protected String doInBackground(String... params) {

    }
    protected void onPostExecute(String result){
        if(page.contains("error")) //when not subscribed
        {   
           if(builder!=null){
                builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int whichButton){
                    dialog.dismiss();
                        if(!<condition>)
                        {
                        try
                        {
                        String pl = ""; 

                        mHelper.<flow>(<class>.this, SKU, RC_REQUEST, 
                        <listener>, pl);
                        }

                        catch(Exception e)
                        {
                        e.printStackTrace();
                        }
                    }  
                }
            });

            builder.show();
        }
    }

}
}

-4

bu globals değişkenleri fikriyle MainActivity örneğini onCreate () içine kaydettim; Android genel değişkeni

public class ApplicationController extends Application {

    public static MainActivity this_MainActivity;
}

ve bunun gibi diyaloğu aç. işe yaradı.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Global Var
    globals = (ApplicationController) this.getApplication();
    globals.this_MainActivity = this;
}

ve bir ileti dizisinde bunun gibi bir iletişim kutusu açıyorum.

AlertDialog.Builder alert = new AlertDialog.Builder(globals.this_MainActivity);
  1. MainActivity'yi açın
  2. Bir ileti dizisi başlatın.
  3. İş parçacığından iletişim kutusunu aç -> iş.
  4. "Geri düğmesi" ne tıklayın (onCreate çağrılacak ve ilk MainActivity'yi kaldıracak)
  5. Yeni MainActivity başlayacaktır. (ve örneğini globallere kaydedin)
  6. İlk iş parçacığından iletişim kutusunu aç -> açılacak ve çalışacaktır.

:)


4
Bir Aktiviteye asla statik referans bırakmayın. Bellek sızıntısına neden olacak
Leandroid
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.