Android: ProgressDialog.show () getApplicationContext ile çöküyor


109

Bunun neden olduğunu anlayamıyorum. Bu kod:

mProgressDialog = ProgressDialog.show(this, "", getString(R.string.loading), true);

gayet iyi çalışıyor. Ancak bu kod:

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

aşağıdaki istisnayı atar:

W/WindowManager(  569): Attempted to add window with non-application token WindowToken{438bee58 token=null}.  Aborting.
D/AndroidRuntime( 2049): Shutting down VM
W/dalvikvm( 2049): threadid=3: thread exiting with uncaught exception (group=0x4001aa28)
E/AndroidRuntime( 2049): Uncaught handler: thread main exiting due to uncaught exception
E/AndroidRuntime( 2049): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.tastekid.TasteKid/com.tastekid.TasteKid.YouTube}: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2401)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.access$2100(ActivityThread.java:116)
E/AndroidRuntime( 2049):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1794)
E/AndroidRuntime( 2049):    at android.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 2049):    at android.os.Looper.loop(Looper.java:123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.main(ActivityThread.java:4203)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2049):    at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
E/AndroidRuntime( 2049):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:549)
E/AndroidRuntime( 2049):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime( 2049): Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
E/AndroidRuntime( 2049):    at android.view.ViewRoot.setView(ViewRoot.java:460)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
E/AndroidRuntime( 2049):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
E/AndroidRuntime( 2049):    at android.app.Dialog.show(Dialog.java:238)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:107)
E/AndroidRuntime( 2049):    at android.app.ProgressDialog.show(ProgressDialog.java:90)
E/AndroidRuntime( 2049):    at com.tastekid.TasteKid.YouTube.onCreate(YouTube.java:45)
E/AndroidRuntime( 2049):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/AndroidRuntime( 2049):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2364)
E/AndroidRuntime( 2049):    ... 11 more

Bunun neden olduğuna dair bir fikriniz var mı? Bunu onCreateyöntemden çağırıyorum .


Kullanıyorsanız Fragment, stackoverflow.com/questions/24825114/…
Yeo

Yanıtlar:


42

Hangi API sürümünü kullanıyorsunuz? Sorunun ne olduğu konusunda haklıysam, bu Android 1.6'da (API sürüm 4) düzeltildi.

getApplicationContext()Dönen nesne başvurusu sadece boşa işaret ediyor gibi görünüyor . Sanırım benim sahip olduğuma benzer bir problem yaşıyorsunuz, çünkü bazı kodlar onCreate()pencere gerçekten inşa edilmeden önce çalıştırılıyor. Bu bir hack olacak, ancak birkaç yüz milisaniye içinde yeni bir İş Parçacığı başlatmayı deneyin (IIRC: 300-400 benim için işe yarıyor gibi görünüyordu, ancak ProgressDialog'unuzu açan ve ihtiyacınız olan diğer her şeyi başlatan) ör. ağ GÇ). Bunun gibi bir şey:

@Override
public void onCreate(Bundle savedInstanceState) {
    // do all your other stuff here

    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            mProgressDialog = ProgressDialog.show(
               YouTube.this.getApplicationContext(), "",
               YouTube.this.getString(R.string.loading), true);

            // start time consuming background process here
        }
    }, 1000); // starting it in 1 second
}

6
1.6 kullanıyorum. Herhangi bir UI işleminin UI iş parçacığında yapılması gerektiğinden oldukça eminim, bu nedenle ProgressDialog.show () 'u ayrı bir iş parçacığında çağırmak kolayca büyük bir sorun olabilir. Yine de bunun tuhaf olduğunu düşünüyorum.
Felix

3
Size verdiğim örnekte, başka bir iş parçacığında UI işlemleri yapmıyorsunuz, diğer iş parçacığı sadece iletişim kutusunu açmasını söyleyen UI iş parçacığına geri çağırıyor.
Jeremy Logan

Kesinlikle garip ve tam bir hack, ama benim için çalıştı. Bunu kullanmayı DURDURABİLECEĞİMİ görmek için 1.6'da yaşadığım hatayı test etmem gerekiyor.
Jeremy Logan

1
Bu 'tuhaf' veya 'tam bir hack' değil, tamamen meşru bir yaklaşım!
KomodoDave

1
@KomodoDave Ben de aynı sorunu yaşadığımı fark ettim. Ancak, kötü hack zamanlayıcıdadır. Bu, bazı durumlarda aralıklı olarak başarısız olmayı bekleyen bir zamanlama penceresidir. Başarının anahtarı, daha kısa bir zamanlayıcı ayarlamak olabilir, uygulamanın hazır olup olmadığını kontrol edin, tamamlanana kadar eylemi yeniden erteleyin. Muhtemelen kaç kez deneneceğini de sınırlandır.
Jim Rush

129

API Seviye 7 ile Android sürüm 2.1 kullanıyorum. Bu (veya benzeri) sorunla karşılaştım ve bunu kullanarak çözdüm:

Dialog dialog = new Dialog(this);

bunun yerine:

Dialog dialog = new Dialog(getApplicationContext());

Bu yardımcı olur umarım :)


4
Benzer bir sorun yaşadım, ancak bir ActivityGroup kullanıyordum. Bu hatayı çözebilmemin tek yolu bunun yerine getParent () kullanmaktı.
Brack

20
Bu onun sorusuna nasıl cevap veriyor? Birincisi işe yararken ikincisi NEDEN çalışmıyor diye soruyor.
Burkhard

3
-1, 'bu', bazılarımız için 'getApplicationContext ()' ile aynıdır.
kellogs

2.1 için geliştirme konusunda hala yararlı bir ipucu
Carlos P

64

Benim için değişmeye çalıştım

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

için

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

Garip olan şey, ilki google öğreticide bulunabilir ve insanlar bu konuda hata alırlar ..


1
bir onclick etkinliğinde bir uyarı ile benim için çalışan tek çözüm
Tobias

Bunu yapmanın doğru yolu budur. Kesinlikle gerekli olmadıkça ve hepsinden önemlisi ApplicationContext'i asla kullanmayın, asla UI öğelerini görüntülemek için kullanmayın. Faaliyetler (ve nihayetinde parçalar) bunun içindir.
Martin Marconcini

İşte bu o. thisÖrneğin bir tıklama dinleyicisi içinde yapıyorsanız, tek başına çalışmayacaktır.
Ayman Salah

23

Bunun boş bir uygulama bağlamıyla ilgili bir zamanlama sorunu olduğunu düşünmüyorum

Uygulamanızı genişletmeyi deneyin (veya zaten varsa sadece kullanın)

public class MyApp extends Application

Örneği özel bir singleton olarak kullanılabilir hale getirin. Bu asla boş değildir

private static MyApp appInstance;

Uygulamamda statik bir yardımcı olun (tekli kullanacaktır)

    public static void showProgressDialog( CharSequence title, CharSequence message )
{
    prog = ProgressDialog.show(appInstance, title, message, true); // Never Do This!
}

BOOM!!

Ayrıca, android mühendisinin cevabına buradan göz atın : WindowManager $ BadTokenException

Bu hatanın bir nedeni, bir Etkinlik olmayan bir Bağlam üzerinden bir uygulama penceresi / iletişim kutusu görüntülemeye çalışmak olabilir.

Şimdi, kabul ediyorum, yöntemin Activity yerine bir Bağlam parametresi almasının bir anlamı yok ..


10

Yukarıdaki cevapları okuduktan sonra, durumum için aşağıdakilerin sorunu çözdüğünü öğrendim.

Bu hatayı attı

myButton.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
        MyDialogue dialog = new MyDialogue(getApplicationContext());
        dialog.show();              
    }
});

Bağlamın yanlış olduğunu öne süren önceki yanıtlara dayanarak, onClick yöntemine iletilen View'dan bağlamı almak için getApplicationContext () öğesini değiştirdim.

myButton.setOnClickListener(new OnClickListener(){
    public void onClick(View v) {
        MyDialogue dialog = new MyDialogue(v.getContext());
        dialog.show();              
    }
});

Java'nın işleyişini tam olarak anlamadığım için yanılıyor olabilirim, ancak benim özel durumum için nedenin yukarıdaki ön bilginin bir Soyut Aktivite sınıfında tanımlanmış olmasından kaynaklanabileceğini tahmin ediyorum; birçok Etkinlik tarafından miras alınır ve kullanılır, belki de getApplicationContext () 'in geçerli bir bağlam döndürmemesine katkıda bulunan budur ?? (Sadece bir tahmin).


Daha iyi puanlanmış çözümler muhtemelen çoğu durumda işe yarar, ancak v.getContext () tekniğiniz benimki gibi en inatçı vakaları çözüyor gibi görünüyor. Deneysel java bilgim, onCreated yönteminden gelen bir bağlamın, bir onClick yönteminin Görünümünden gelen bağlamla tam olarak aynı olmadığını düşünmeme neden oluyor. Oyvermek!
Josh

Bu benim günümü kurtardı!
Alejandro Luengo

6

Maddeleştirilmiş kaplamalara sahip bir harita görünümü oluşturuyorum. Ben haritamdan bu şekilde itemizedoverlay'ımı oluşturuyordum

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

"Android.view.WindowManager $ BadTokenException: Pencere eklenemiyor - jeton null bir uygulama için değil" istisnasını, itemizedoverlay'ım onTap yöntemim tetiklendiğinde (harita görünümünde konuma dokunulduğunda) alacağımı buldum.

Kurucuma 'getApplicationContext ()' yerine basitçe 'this' geçersem sorunun ortadan kalktığını buldum. Bu, alienjazzcat'in sonucunu destekliyor gibi görünüyor. tuhaf.


1
Teşekkürler, sorunum tam olarak buydu.
Kon

4

TabActivities içinde gösterilen Etkinlikler için getParent () kullanın

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

onun yerine

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

3

Android 2.2 için
Bu kodu kullanın:

//activity is an instance of a class which extends android.app.Activity
Dialog dialog = new Dialog(activity);

bu kod yerine:

// this code produces an ERROR:
//android.view.WindowManager$BadTokenException: 
//Unable to add window -- token null is not for an application
Context mContext = activity.getApplicationContext();
Dialog dialog = new Dialog(mContext);

Açıklama: Özel diyaloğum activity.onCreateDialog(int dialogId)yöntem dışında oluşturuldu .



2

(Uyumluluk) fragmanlar olan bir kullanarak benzer bir sorun vardı getActivity()içindeProgressDialog.show() çöker. Zamanlamadan kaynaklandığına katılıyorum.

Olası bir düzeltme:

mContext = getApplicationContext();

if (mContext != null) {
    mProgressDialog = ProgressDialog.show(mContext, "", getString(R.string.loading), true);
}

kullanmak yerine

mProgressDialog = ProgressDialog.show(getApplicationContext(), "", getString(R.string.loading), true);

Bağlamı kavramasına daha fazla zaman vermek için mContext'i olabildiğince erken yerleştirin. Hala bunun işe yarayacağına dair bir garanti yok, sadece çökme olasılığını azaltıyor. Hala çalışmıyorsa, zamanlayıcı hackine başvurmanız gerekir (bu, daha sonra iletişim kutusunu kapatmak gibi diğer zamanlama sorunlarına neden olabilir).

Elbette, thisveya kullanabiliyorsanız ActivityName.this, daha kararlıdır çünkü thiszaten bir şeye işaret eder. Ancak bazı durumlarda, belirli Fragment mimarilerinde olduğu gibi, bu bir seçenek değildir.


2

(Gelecekteki referanslar için)

Sanırım, burada açıklandığı gibi Uygulama Bağlamında ve Etkinlik Bağlamında farklılıklar olduğu için: http://www.doubleencore.com/2013/06/context/

Bu, Uygulama Bağlamını kullanarak iletişim kutusu gösteremeyeceğimiz anlamına gelir. Bu kadar.


2

Aktivitelerin içindeki diyalogları kullanmak için bunu şu şekilde yapın:

private Context mContext;
private AlertDialog.Builder mBuilder;

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

     //using mContext here refering to activity context
     mBuilder = new AlertDialog.Builder(mContext);
     //...
     //rest of the code
     //...
}

Parçaların içindeki diyalogları kullanmak için bunu şu şekilde yapın:

private Context mContext;
private AlertDialog.Builder mBuilder;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      View mRootView = inflater.inflate(R.layout.fragment_layout, container, false);
      mContext = getActivity();

      //using mContext here refering to fragment's hosting activity context
      mBuilder = new AlertDialog.Builder(mContext);
      //...
      //rest of the code
      //...
      return mRootView;
}

İşte bu ^ _ ^


1

Bunu aşmak için yaptığım şey, küresel verileri depoladığım tüm etkinliklerim için bir temel sınıf oluşturmaktı. İlk aktivitede, bağlamı temel sınıfımdaki bir değişkene şöyle kaydettim:

Temel Sınıf

public static Context myucontext; 

Temel Sınıftan türetilen İlk Etkinlik

mycontext = this

Ardından, diyaloglar oluştururken getApplicationContext yerine kendi bağlamımı kullanıyorum.

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

Bu çözümün daha fazla oy almaması ne yazık. Olası çözümler Burada sunulan tüm dışında, bu bir AsyncTask benim için çalıştı tek şey
CKN

1

Bir parça içinde ProgressDialog.show () 'u çağırıyorsanız, mContext'i Activity'e dönüştürmek benim için çalıştı.

     ProgressDialog pd = new ProgressDialog((Activity) mContext);

1

Bu yaygın bir sorundur. thisBunun yerine kullanın getApplicationContext() sorununuzu çözmeli


0

Mevcut aktivite görünümüne istisna atma için Uyarı İletişim Kutusunu uyguladım.

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

Aynı Pencere İstisnası verildiğinde. OnCreate () 'den uyarı için kod yazıyorum. Çok basit yöntemdeki ifadeden context = this;sonra kullandım. Bağlam değişkenini küresel gibi aldısetContentView()onCreate()Context context;

Kod örneği

static Context context;

 public void onCreate(Bundle savedInstanceState)  { 
        super.onCreate(savedInstanceState); 


        setContentView(R.layout.network); 
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        context = this;
.......

Uyarı Yöntemi Örneği

private void alertException(String execMsg){
        Log.i(TAG,"in alertException()..."+context);
        Log.e(TAG,"Exception :"+execMsg);
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
.......

Benim için gayet iyi çalışıyor.Aslında StackOverflow'da bu hatayı aradım bu sorguyu buldum.Bu yazının tüm yanıtlarını okuduktan sonra bu şekilde denedim ve işe yarıyor. Bunun istisnayı aşmak için basit bir çözüm olduğunu düşündüm.

Teşekkürler Rajendar


0

groupActivity'de bir sorununuz varsa bunu kullanmayın. PARENT, Üst Etkinlik Grubundan bir statiktir.

final AlertDialog.Builder builder = new AlertDialog.Builder(GroupActivityParent.PARENT);

onun yerine

final AlertDialog.Builder builder = new AlertDialog.Builder(getParent());

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.