Android:ProgressDialog.show()がgetApplicationContextでクラッシュする


109

なぜこれが起こっているのか理解できません。このコード:

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

正常に動作します。ただし、このコード:

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

次の例外をスローします。

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

なぜこれが起こっているのですか?これをonCreateメソッドから呼び出しています。


を使用している場合Fragmentstackoverflow.com / questions / 24825114
Yeo

回答:


42

どのAPIバージョンを使用していますか?問題が何であるかについて私が正しい場合、これはAndroid 1.6(APIバージョン4)で修正されました。

getApplicationContext()nullを指すオブジェクト参照のように見えます。onCreate()ウィンドウが実際に構築される前にのコードの一部が実行されているという点で、私が抱えていたのと同様の問題が発生していると思います。これはハックになりますが、ProgressDialogを開き、必要な他の処理を開始する新しいスレッドを数百ミリ秒(IIRC:300-400でうまくいくように見えますが、いじくり回す必要があります)で起動してみてください(例:ネットワークIO)。このようなもの:

@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を使用しています。UI操作はすべてUIスレッドで実行する必要があると確信しているため、別のスレッドでProgressDialog.show()を呼び出すと、簡単に大きな問題になる可能性があります。まだこれは奇妙だと思います。
フェリックス

3
私があなたに与えた例では、別のスレッドでUI操作を行っていません。他のスレッドは、ダイアログを開くように指示するUIスレッドにコールバックしているだけです。
ジェレミーローガン、

それは間違いなく奇妙で、それは完全なハックですが、それは私にとってはうまくいきました。私は1.6にあったバグをテストして、これを使用して停止できるかどうかを確認する必要があります。
ジェレミーローガン

1
それは「奇妙な」ものではなく、「完全なハック」でもありません。それは完全に正当なアプローチです!
KomodoDave、

1
@KomodoDave私は同じ問題があることに気づきました。ただし、悪いハックはタイマーにあります。これは、状況によっては断続的に失敗するのを待つタイミングウィンドウです。成功の鍵は、タイマーを短く設定することかもしれません。アプリケーションの準備ができているかどうかを確認し、準備ができるまでアクションを再遅延します。おそらく何回も試す回数を制限してください。
ジムラッシュ

129

私はAPIレベル7のAndroidバージョン2.1を使用しています。この(または同様の)問題に直面し、これを使用して解決しました。

Dialog dialog = new Dialog(this);

これの代わりに:

Dialog dialog = new Dialog(getApplicationContext());

お役に立てれば :)


4
同様の問題がありましたが、ActivityGroupを使用していました。このエラーを解決できた唯一の方法は、代わりにgetParent()を使用することでした。
Brackの

20
これは彼の質問にどのように答えますか?彼は、2つ目が機能しないのに1つ目は機能する理由を尋ねます。
Burkhard

3
-1、「this」は、一部の人にとっては「getApplicationContext()」と同じです。
ケルログ2011

2.1の開発に役立つヒント
Carlos P

64

私にとっては変化に取り組みました

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

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

奇妙なことに、最初のものがgoogle tutorialにあり、人々はこれについてエラーを受け取ります。


1
onclickイベント内のアラートで私のために働く唯一のソリューション
Tobias

これが正しい方法です。厳密に必要な場合を除いて、ApplicationContextを使用しないでください。また、UI要素を表示するために使用しないでください。それがアクティビティ(そして最終的にはフラグメント)の目的です。
Martin Marconcini、2013年

これです。thisたとえば、クリックリスナー内でそれを実行している場合、単独では機能しません。
Ayman Salah 2016

23

これはnullアプリケーションコンテキストのタイミングの問題ではないと思います

アプリ内でアプリケーションを拡張してみてください(すでに持っている場合はそれを使用してください)

public class MyApp extends Application

インスタンスをプライベートシングルトンとして使用できるようにします。これがnullになることはありません

private static MyApp appInstance;

MyAppで静的ヘルパーを作成します(シングルトンを使用します)。

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

ブーム!!

また、こちらのandroidエンジニアの回答もご覧ください。 WindowManager $ BadTokenException

このエラーの原因の1つは、アクティビティではないコンテキストを介してアプリケーションウィンドウ/ダイアログを表示しようとしていることです。

同意しますが、メソッドがアクティビティではなくコンテキストパラメータを取ることは意味がありません。


10

上記の回答を読んだところ、私の状況では、次の問題が修正されたことがわかりました。

これはエラーを投げました

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

コンテキストが間違っていると示唆した以前の回答に基づいて、ボタンのonClickメソッドに渡されたビューからコンテキストを取得するようにgetApplicationContext()を変更しました。

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

私はJavaの動作を完全に理解していないので間違っている可能性がありますが、私の特定の状況では、原因は上記のスニペットがAbstract Activityクラスで定義されているという事実に関連している可能性があります。多くのアクティビティによって継承および使用され、おそらくgetApplicationContext()が有効なコンテキストを返さないという事実に貢献しましたか?(推測)。


より良いスコアのソリューションはおそらくほとんどの場合に機能しますが、v.getContext()テクニックは私のような最も頑固なケースを解決するようです。私の経験的なJavaの知識により、onCreatedメソッドからのコンテキストは、onClickメソッドのビューからのコンテキストとまったく同じではないと思います。投票してください!
ジョシュ14

これは私の日を救った!
アレハンドロルエンゴ2018年

6

アイテム化されたオーバーレイを使用してマップビューを作成しています。私は私のmapActivityから次のようなitemizedoverlayを作成していました:

OCItemizedOverlay currentLocationOverlay = new OCItemizedOverlay(pin,getApplicationContext);

itemizedoverlayのonTapメソッドがトリガーされたとき(マップビューで場所がタップされたとき)、「android.view.WindowManager $ BadTokenException:Unable to add window-token null is not for the application」例外が発生することがわかりました。

単に「getApplicationContext()」ではなく「this」をコンストラクターに渡した場合、問題は解消されました。これは、alienjazzcatの結論をサポートしているようです。変。


1
ありがとう、これはまさに私の問題でした。

4

TabActivities内に表示されるアクティビティには、getParent()を使用します

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

の代わりに

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

3

Android 2.2の場合
、次のコードを使用します。

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

このコードの代わりに:

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

注釈:カスタムダイアログはactivity.onCreateDialog(int dialogId)メソッドの外部で作成されます。


3

試してください-

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

現在のアクティビティがアクティビティ
グループ

2

getActivity()内で使用する(互換性)フラグメントに同様の問題があったProgressDialog.show()クラッシュするた。タイミングの問題だと思います。

可能な修正:

mContext = getApplicationContext();

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

使用する代わりに

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

mContextをできるだけ早く配置して、コンテキストを取得する時間を増やします。これが機能するという保証はまだありません。クラッシュの可能性を減らすだけです。それでも機能しない場合は、タイマーハックを使用する必要があります(後でダイアログを閉じるなど、他のタイミングの問題が発生する可能性があります)。

もちろん、thisまたはを使用できる場合はActivityName.thisthisすでに何かを指しているため、より安定しています。しかし、一部のケースでは、特定のフラグメントアーキテクチャのように、それはオプションではありません。


2

(将来の参考のために)

ここで説明するように、アプリケーションコンテキストとアクティビティコンテキストに違いがあるためだと思います。http//www.doubleencore.com/2013/06/context/

つまり、アプリケーションコンテキストを使用してダイアログを表示することはできません。それでおしまい。


2

アクティビティ内でダイアログを使用するには、次のようにします。

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

フラグメント内でダイアログを使用するには、次のようにします。

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

それだけです^ _ ^


1

これを回避するために行ったのは、グローバルデータを格納するすべてのアクティビティの基本クラスを作成することでした。最初のアクティビティでは、次のようにコンテキストを基本クラスの変数に保存しました。

基本クラス

public static Context myucontext; 

基本クラスから派生した最初のアクティビティ

mycontext = this

次に、ダイアログを作成するときに、getApplicationContextの代わりにmycontextを使用します。

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

この解決策がこれ以上の賛成票を得ることはありません。ここに提示されたすべての可能な解決策の中で、これは私にとってAsyncTaskで機能した唯一のものです
ckn

1

フラグメントでProgressDialog.show()を呼び出す場合は、mContextをActivityにキャストするとうまくいきました。

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


0

例外が現在のアクティビティビューにスローされるようにアラートダイアログを実装しました。

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

同じウィンドウ例外を指定します。onCreate()からアラートのコードを記述します。シンプルなので、メソッドのcontext = this;after setContentView()ステートメントを使用します。onCreate()Context context;

コードサンプルは

static Context context;

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


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

        context = this;
.......

アラートメソッドのサンプルは

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

これは正常に機能します。実際には、StackOverflowでこのエラーを検索しましたが、このクエリが見つかりました。この投稿のすべての応答を読んだ後、この方法を試してみました。これは機能します。これは、例外を克服するための簡単な解決策だと思いました。

ありがとう、ラジェンダー


0

groupActivityに問題がある場合は、これを使用しないでください。PARENTは、Parent ActivityGroupのstaticです。

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

の代わりに

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.