進行中の学習プロセス(今回はダイアログボックス)で、これが機能することを発見しました。
AlertDialog.Builder builder = new AlertDialog.Builder(this);
以下は機能しません(実行時にWindowManager $ BadTokenExceptionで失敗します)。
AlertDialog.Builder builder = new AlertDialog.Builder(this.getApplicationContext());
AlertDialog.Builderの コンストラクタ は、ActivityではなくContextをパラメータとして受け入れるように定義されているため、理由はわかりません。
public AlertDialog.Builder(コンテキストコンテキスト)
このビルダーのコンテキストとそれが作成するAlertDialogを使用するコンストラクター。
何が欠けていますか?
アクティビティはコンテキストを継承します。 AlertDialog.Builderは、Context引数を指定します。これは、Activity、ListActivity、Serviceなどを含む、ContextのサブクラスであるANYクラスで使用できるためです(これの背後に共通のコーディングイディオムがあります-詳細についてはこちらをご覧ください)ジョシュア・ブロッホの素晴らしい効果的なJavaの(インターフェースと抽象クラスの)項目I8を読んでください。
getApplicationContext()は、アプリケーションのコンテキストを返します。これは、ほとんどの場合、アクティビティコンテキストと同じです。そして、「ほとんど」がユーザーをスローします。詳細は不明ですが、これは広く発生している問題であり、一般的な答えは、画面にアラートを書き込むコンテキストを使用することです。これはnot getApplicationContext()によって返されるものであることに注意してください。
私のような人なら、「しかし、Activityから継承しないクラスで作業しているので、そもそもこのためにgetApplicationContext()を使用したいのですが」私は実際にはそんなに失礼な話をしていません; p ..要点は私もここにいたことです。私はそれを次のように修正しました。1)「アクティビティ間で、またはListActivities、Services、...でさえ共有したいので、UI AlertDialogコードを非アクティビティクラスに持っていますか?」と自問します。そうでない場合、うーん...本当にUIへのアクセス(つまりコンテキスト)を保証できないコードにAlertDialog UI呼び出しがありますか?その場合は、設計を再検討してください。
このクラスを複数のアクティビティで共有したいと想定すると、答えが明らかになります。さまざまな呼び出し元がクラスを使用できるようにしたいので、それぞれが独自のコンテキストを持つ可能性があります。したがって、呼び出し元はそのコンテキストを引数としてクラスに渡す必要があります。
myClass(Context theContext, ...) { ... }
各アクティビティ、サービスなどは、次のように呼び出します。
myClass(this, ...);
見覚えがあります?
注意してください!コードを共有している場合は、さまざまな影響をすべて受けながら、共有コードにさまざまな呼び出しが並行して入る可能性を考慮する必要があります。ここでは範囲を超えています...
楽しんで :)
AlertDialog は Dialog のサブクラスで、関連する Window は関連 LayoutParams があります。それらのパラメータの1つは、ウィンドウの type です。デフォルトのタイプは TYPE_APPLICATION_ATTACHED_DIALOG で、親ウィンドウが必要です。
アクティビティに関連付けられた WindowManager は、アクティビティのウィンドウを親ウィンドウとして使用するように構成されています。アプリケーションに関連付けられたWindowManagerには、関連付けられた親ウィンドウがありません。
結論:ダイアログを正常に表示するには、デフォルトのウィンドウタイプを親ウィンドウを必要としないタイプに変更するか、または親ウィンドウが関連付けられているコンテキストを使用する必要があります。