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.

Felix
quelle
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
}
Jeremy Logan
quelle
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 :)

Taner
quelle
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.

wtk
quelle
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.

alienjazzcat
quelle
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).

Emile
quelle
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.

Chiffrez
quelle
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);
salcosand
quelle
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.

jm_java
quelle
3

Versuchen -

AlertDialog.Builder builder = new AlertDialog.Builder(getParent());
eyal
quelle
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.

Muz
quelle
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.

vtloc
quelle
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 ^ _ ^

Blueware
quelle
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();
Regenhütte
quelle
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);
Dale Julian
quelle
1

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

Atul Kumar
quelle
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

Rajendar
quelle
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());
vilvestre
quelle