Android: ProgressDialog.show () stürzt mit getApplicationContext ab


109

Ich kann nicht verstehen, warum dies geschieht. Dieser Code:

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

funktioniert gut. Dieser Code jedoch:

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

löst die folgende Ausnahme aus:

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

Irgendwelche Ideen, warum das passiert? Ich rufe dies von der onCreateMethode auf.


Wenn Sie verwenden Fragment, stackoverflow.com/questions/24825114/…
Yeo

Antworten:


42

Welche API-Version verwenden Sie? Wenn ich mit dem Problem Recht habe, wurde dies in Android 1.6 (API-Version 4) behoben.

Es sieht so aus, als ob die Objektreferenz, getApplicationContext()die zurückgibt, nur auf null zeigt. Ich denke, Sie haben ein ähnliches Problem wie ich, da ein Teil des Codes in ausgeführt onCreate()wird, bevor das Fenster tatsächlich erstellt wird. Dies wird ein Hack sein, aber versuchen Sie, in wenigen hundert Millisekunden einen neuen Thread zu starten (IIRC: 300-400 schien für mich zu funktionieren, aber Sie müssen basteln), der Ihren ProgressDialog öffnet und alles andere startet, was Sie benötigen ( zB Netzwerk IO). Etwas wie das:

@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
Ich benutze 1.6. Ich bin mir ziemlich sicher, dass alle UI-Operationen im UI-Thread ausgeführt werden sollten, daher könnte das Aufrufen von ProgressDialog.show () in einem separaten Thread leicht ein großes Problem sein. Ich finde das immer noch komisch.
Felix

3
In dem Beispiel, das ich Ihnen gegeben habe, führen Sie keine UI-Operationen in einem anderen Thread aus. Der andere Thread ruft nur den UI-Thread zurück und fordert ihn auf, den Dialog zu öffnen.
Jeremy Logan

Es ist definitiv komisch und ein totaler Hack, aber es hat bei mir funktioniert. Ich muss den Fehler, den ich in 1.6 hatte, testen, um zu sehen, ob ich damit aufhören kann.
Jeremy Logan

1
Es ist weder "seltsam" noch ein "totaler Hack", es ist ein absolut legitimer Ansatz!
KomodoDave

1
@KomodoDave Ich habe gerade festgestellt, dass ich das gleiche Problem habe. Der schlechte Hack liegt jedoch im Timer. Dies ist ein Zeitfenster, das darauf wartet, in einigen Situationen zeitweise fehlzuschlagen. Der Schlüssel zum Erfolg könnte darin liegen, einen kürzeren Timer einzustellen. Überprüfen Sie, ob die Anwendung bereit ist, und verschieben Sie die Aktion erneut, bis sie fertig ist. Beschränken Sie wahrscheinlich auch, wie oft Sie es versuchen sollen.
Jim Rush

129

Ich verwende Android Version 2.1 mit API Level 7. Ich bin mit diesem (oder einem ähnlichen) Problem konfrontiert und habe Folgendes gelöst:

Dialog dialog = new Dialog(this);

an Stelle von:

Dialog dialog = new Dialog(getApplicationContext());

Hoffe das hilft :)


4
Ich hatte ein ähnliches Problem, verwendete jedoch eine ActivityGroup. Die einzige Möglichkeit, diesen Fehler zu beheben, war die Verwendung von getParent ().
Brack

20
Wie beantwortet dies seine Frage? Er fragt, warum der zweite nicht funktioniert, während der erste funktioniert.
Burkhard

3
-1, 'this' ist für einige von uns genau das gleiche wie 'getApplicationContext ()'.
Kellogs

Immer noch ein nützlicher Tipp für 2.1
Carlos P

64

Für mich hat sich verändert

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

zu

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

Seltsame Sache ist, dass die erste in Google Tutorial gefunden werden kann und die Leute Fehler in diesem Fall bekommen.


1
einzige Lösung, die für mich mit einem Alarm innerhalb eines Onclick-Ereignisses funktioniert
Tobias

Dies ist der richtige Weg. Verwenden Sie ApplicationContext niemals, es sei denn, dies ist unbedingt erforderlich, und verwenden Sie ihn niemals zur Anzeige von UI-Elementen. Dafür sind Aktivitäten (und letztendlich Fragmente) gedacht.
Martin Marconcini

Das ist der eine. thisAlleine funktioniert nicht, wenn Sie dies beispielsweise in einem Klick-Listener tun.
Ayman Salah

23

Ich denke nicht, dass dies ein Zeitproblem in einem Null-Anwendungskontext ist

Versuchen Sie, die Anwendung in Ihrer App zu erweitern (oder verwenden Sie sie einfach, wenn Sie dies bereits getan haben).

public class MyApp extends Application

Stellen Sie die Instanz als privaten Singleton zur Verfügung. Dies ist niemals null

private static MyApp appInstance;

Erstellen Sie einen statischen Helfer in MyApp (der den Singleton verwendet).

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

BOOM!!

Schauen Sie sich auch die Antwort des Android-Ingenieurs hier an: WindowManager $ BadTokenException

Eine Ursache für diesen Fehler ist möglicherweise der Versuch, ein Anwendungsfenster / -dialogfeld über einen Kontext anzuzeigen, der keine Aktivität ist.

Nun, ich stimme zu, es macht keinen Sinn, dass die Methode einen Kontextparameter anstelle von Aktivität verwendet.


10

Nachdem ich die obigen Antworten gelesen hatte, stellte ich fest, dass das Problem für meine Situation durch Folgendes behoben wurde.

Dies warf den Fehler

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

Basierend auf den vorherigen Antworten, die darauf hinwiesen, dass der Kontext der falsche war, habe ich getApplicationContext () geändert, um den Kontext aus der Ansicht abzurufen, die an die onClick-Methode der Schaltflächen übergeben wurde.

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

Ich verstehe die Funktionsweise von Java nicht vollständig, daher könnte ich mich irren, aber ich vermute, dass die Ursache für meine spezielle Situation mit der Tatsache zusammenhängen könnte, dass das obige Snippet in einer abstrakten Aktivitätsklasse definiert wurde. geerbt und von vielen Aktivitäten verwendet, hat das vielleicht dazu beigetragen, dass getApplicationContext () keinen gültigen Kontext zurückgibt? (Nur eine Vermutung).


Die besser bewerteten Lösungen funktionieren wahrscheinlich in den meisten Fällen, aber Ihre v.getContext () -Technik scheint die hartnäckigsten Fälle wie meine zu lösen. Mein empirisches Java-Wissen lässt mich denken, dass ein Kontext, der aus einer onCreated-Methode stammt, nicht genau der gleiche ist wie ein Kontext, der aus der Ansicht einer onClick-Methode stammt. Stimmen Sie ab!
Josh

Das hat mir den Tag gerettet!
Alejandro Luengo

6

Ich erstelle eine Kartenansicht mit detaillierten Überlagerungen. Ich habe mein Element-Overlay wie folgt aus meiner mapActivity erstellt:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

Ich habe festgestellt, dass die Ausnahme "android.view.WindowManager $ BadTokenException: Fenster - Token null kann nicht für eine Anwendung hinzugefügt werden" angezeigt wird, wenn die onTap-Methode meines itemizedoverlay ausgelöst wurde (wenn der Speicherort in der Kartenansicht angetippt wird).

Ich stellte fest, dass das Problem behoben wurde, wenn ich einfach 'this' anstelle von 'getApplicationContext ()' an meinen Konstruktor übergab. Dies scheint die Schlussfolgerung von alienjazzcat zu stützen. seltsam.


1
Danke, genau das war mein Problem.
Kon

4

Verwenden Sie für in TabActivities angezeigte Aktivitäten getParent ()

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

anstatt

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

3

Für Android 2.2
Verwenden Sie diesen Code:

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

anstelle dieses Codes:

// 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);

Anmerkung: Mein benutzerdefinierter Dialog wird außerhalb der activity.onCreateDialog(int dialogId)Methode erstellt.


3

Versuchen -

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

Wird

2

Hatte ein ähnliches Problem mit (Kompatibilität) Fragmente , bei dem ein unter Verwendung getActivity()innerhalb ProgressDialog.show()stürzt. Ich würde zustimmen, dass es am Timing liegt.

Eine mögliche Lösung:

mContext = getApplicationContext();

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

anstatt zu verwenden

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

Platzieren Sie den mContext so früh wie möglich, damit Sie mehr Zeit haben, den Kontext zu erfassen. Es gibt immer noch keine Garantie dafür, dass dies funktioniert. Es verringert lediglich die Wahrscheinlichkeit eines Absturzes. Wenn es immer noch nicht funktioniert, müssen Sie auf den Timer-Hack zurückgreifen (was andere Timing-Probleme verursachen kann, z. B. das spätere Schließen des Dialogfelds).

Wenn Sie thisoder verwenden können ActivityName.this, ist es natürlich stabiler, weil es thisbereits auf etwas hinweist. In einigen Fällen, wie bei bestimmten Fragment-Architekturen, ist dies jedoch keine Option.


2

(Für zukünftige Referenzen)

Ich denke, das liegt daran, dass es Unterschiede im Anwendungskontext und im Aktivitätskontext gibt, wie hier erläutert: http://www.doubleencore.com/2013/06/context/

Dies bedeutet, dass wir keinen Dialog im Anwendungskontext anzeigen können. Das ist es.


2

Gehen Sie folgendermaßen vor, um Dialoge in Aktivitäten zu verwenden:

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
     //...
}

Gehen Sie folgendermaßen vor, um Dialoge in Fragmenten zu verwenden:

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;
}

Das war's ^ _ ^


1

Um dies zu umgehen, habe ich eine Basisklasse für alle meine Aktivitäten erstellt, in der ich globale Daten speichere. In der ersten Aktivität habe ich den Kontext in einer Variablen in meiner Basisklasse wie folgt gespeichert:

Basisklasse

public static Context myucontext; 

Erste Aktivität abgeleitet von der Basisklasse

mycontext = this

Dann verwende ich beim Erstellen von Dialogen mycontext anstelle von getApplicationContext.

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

Schade, dass diese Lösung keine Up-Votes mehr bekommt. Von allen hier vorgestellten möglichen Lösungen ist dies das einzige, was für mich in einer AsyncTask funktioniert hat
ckn

1

Wenn Sie ProgressDialog.show () in einem Fragment aufrufen, hat das Umwandeln des mContext in Aktivität für mich funktioniert.

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

1

Dies ist ein häufiges Problem. Verwenden Sie thisstattdessen getApplicationContext() Das sollte Ihr Problem lösen


0

Ich habe den Warnungsdialog für Ausnahmen implementiert, die auf die aktuelle Aktivitätsansicht übertragen werden. Wann immer ich dies angegeben habe

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

Angesichts der gleichen Fensterausnahme. Ich schreibe Code für die Warnung aus onCreate (). So einfach, dass ich die context = this;after- setContentView()Anweisung in onCreate()method verwendet habe. Kontextvariable als global ähnlich genommenContext context;

Codebeispiel ist

static Context context;

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


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

        context = this;
.......

Beispiel für eine Warnmethode ist

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

Es funktioniert gut für mich. Eigentlich habe ich bei StackOverflow nach diesem Fehler gesucht. Ich habe diese Abfrage gefunden. Nachdem ich alle Antworten dieses Beitrags gelesen hatte, habe ich es auf diese Weise versucht, damit es funktioniert. Ich dachte, dies ist eine einfache Lösung, um die Ausnahme zu überwinden.

Danke, Rajendar


0

Wenn Sie ein Problem mit groupActivity haben, verwenden Sie dieses nicht. PARENT ist eine statische Datei aus der übergeordneten Aktivitätsgruppe.

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

anstatt

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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.