web-dev-qa-db-ja.com

コンテキストとしてgetApplication()を使用したダイアログで「ウィンドウを追加できません - トークンnullはアプリケーション用ではありません」

私の活動は、パラメータとしてコンテキストを必要とするAlertDialogを作成しようとしています。私が使用する場合、これは予想通りに動作します。

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

しかし、画面が回転するような単純な操作でもActivityが破棄されて再作成されると、メモリリークが発生する可能性があるため、 "this"をコンテキストとして使用するのは嫌です。 Android開発者のブログの 関連の投稿から

コンテキスト関連のメモリリークを回避する簡単な方法が2つあります。最も明白なものはそれ自身の範囲の外で文脈をエスケープすることを避けることです。上記の例では静的参照の場合を示しましたが、内部クラスとその外部クラスへの暗黙の参照も同様に危険です。 2番目の解決策はアプリケーションコンテキストを使用することです。あなたのアプリケーションが生きていて活動のライフサイクルに依存しない限り、このコンテキストは生き続けるでしょう。コンテキストを必要とする長寿命のオブジェクトを維持する予定の場合は、アプリケーションオブジェクトを覚えておいてください。 Context.getApplicationContext()またはActivity.getApplication()を呼び出すことで簡単に取得できます。

しかしAlertDialog()の場合、例外としてスローされるので、getApplicationContext()getApplication()もコンテキストとしては受け入れられません。

「ウィンドウを追加できません - トークンnullはアプリケーション用ではありません」

参照ごとに: 123 など.

それで、これは本当に "バグ"と見なされるべきです、なぜなら私たちは公式にActivity.getApplication()を使うように勧められていますが、それでも宣伝どおりに機能しないのですか?

ジム

630
gymshoe

getApplicationContext()の代わりに、単にActivityName.thisを使ってください。

1286
Steven L

thisを使ってもうまくいきませんでしたが、MyActivityName.thisはうまくいきました。これがthisを動作させることができなかった人に役立つことを願っています。

183
TrueCoke

引き続きgetApplicationContext()を使用することができますが、使用する前に、このフラグを追加する必要があります:dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)、そしてエラーが表示されません。

マニフェストに次の権限を追加してください。

<uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW" />
55
codezjx

あなたの対話は「コンテキストを必要とする長命のオブジェクト」であってはなりません。ドキュメントは紛らわしいです。基本的にあなたが何かのようなことをするならば:

static Dialog sDialog;

static に注意してください)

それからどこかの活動であなたがした

 sDialog = new Dialog(this);

ローテーションなどで元のアクティビティがリークして、アクティビティが破壊される可能性があります。 (onDestroyでクリーンアップしない限り、ただしその場合はDialogオブジェクトを静的にはしないでしょう)

データ構造によっては、データ構造を静的にしてアプリケーションのコンテキストに基づかせるのが理にかなっていますが、一般的にダイアログのようなUI関連のものには意味がありません。だからこのようなもの:

Dialog mDialog;

...

mDialog = new Dialog(this);

MDialogは静的ではないので、mDialogはアクティビティから解放されるので、問題はなく、アクティビティをリークしてはいけません。

34
Kevin TeslaCoil

「... AlertDialog()の場合、getApplicationContext()もgetApplication()も、例外としてスローされるため、Contextとして使用することはできません。 'ウィンドウを追加できません - トークンnullは使用できません。アプリケーション'"

ダイアログを作成するには、 アクティビティコンテキスト または サービスコンテキスト ではなく、 アプリケーションコンテキスト (getApplicationContext()とgetApplication()の両方でアプリケーションコンテキストを返す)が必要です。 ).

これは、 アクティビティコンテキスト を取得する方法です。

(1)活動またはサービスにおいて:

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

(2)フラグメント内:AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

メモリリークは、オブジェクトのそれ自体への参照(すなわち、オブジェクトのデータを格納するために実際に割り当てられたメモリへの参照)である「this」参照に固有の問題ではない。割り当てられたメモリがその有効寿命を超えた後にガベージコレクタ(GC)が解放できないany割り当てられたメモリが発生します。

ほとんどの場合、変数が範囲外になると、メモリはGCによって回収されます。ただし、変数によって保持されているオブジェクト( "x"など)への参照がそのオブジェクトの有効期間を超えても持続すると、メモリリークが発生する可能性があります。そのため、割り当てられたメモリは、 "x"が参照を保持している限り失われます。これは、GC できないが、そのメモリがまだ参照されている限りメモリを解放するためです。 割り当てられたメモリへの一連の参照 のために、メモリリークが明らかにならないことがあります。このような場合、GCはそのメモリへのすべての参照が削除されるまでメモリを解放しません。

メモリリークを防ぐために、割り当てられたメモリが "this"(または他の参照)によって無期限に参照される原因となる論理エラーについてコードを確認してください。チェーンの参照も確認してください。これは、メモリ使用量を分析し、そのような厄介なメモリリークを見つけるのに役立つツールです。

32
ONE

フラグメントで表示されたカスタムアダプタのコンストラクタを通してコンテキストを送信する必要があり、getApplicationContext()でこの問題がありました。私はそれを解決しました:

フラグメントのonCreateコールバックのthis.getActivity().getWindow().getContext()

23
Grux

アクティビティ だけに使用:

MyActivity.this

の中に:

getActivity();
21
Mahmoud Ayman

ダイアログボックスを表示しているボタンをクリックするとActivity

Dialog dialog = new Dialog(MyActivity.this);

私のために働きました。

19
P_Pran

ちょっとしたハック:あなたはGCによってあなたの活動を破壊することを防ぐことができます(そうするべきではありませんが、状況によっては助けになることができます。不要になったらcontextForDialognullに設定することを忘れないでください):

public class PostActivity extends Activity  {
    ...
    private Context contextForDialog = null;
    ...
    public void onCreate(Bundle savedInstanceState) {
        ...
        contextForDialog = this;
    }
    ...
    private void showAnimatedDialog() {
        mSpinner = new Dialog(contextForDialog);
        mSpinner.setContentView(new MySpinner(contextForDialog));
        mSpinner.show();
    }
    ...
}
18
Mikalai Daronin

フラグメントを使用しており、AlertDialog/Toastメッセージを使用している場合は、コンテキストパラメータでgetActivity()を使用します。

このような

ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();
13
muaaz

*****コトリンバージョン*****

applicationContextbaseContextの代わりに[email protected]を渡すべきです

11
MilaDroid

私はフラグメントでProgressDialogを使用していて、コンストラクタパラメータとしてgetActivity().getApplicationContext()を渡すことでこのエラーを得ていました。 getActivity().getBaseContext()に変更してもうまくいきませんでした。

私のために働いた解決策はgetActivity()を渡すことでした。すなわち.

progressDialog = new ProgressDialog(getActivity());

9
T.M

追加

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

そして

マニフェストの"Android.permission.SYSTEM_ALERT_WINDOW"/>

それは今私のために働きます。アプリケーションを閉じて開いた後も、そのときにエラーが発生しました。

9
AlphaStack

あなたがActivityの外にいるなら、あなたはActivityアクティビティとしてあなたの関数 "NameOfMyActivity.this"で使う必要があります、例えば:

public static void showDialog(Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("Your Message")
        .setPositiveButton("Yes", dialogClickListener)
        .setNegativeButton("No", dialogClickListener).show();
}


//Outside your Activity
showDialog(NameOfMyActivity.this);
6
oabareload

MyDialog md = new MyDialog(MyActivity.this.getParent());を使う

6
MSA

ダイアログの下にあるアクティビティのコンテキストを使用するようにしてください。しかし、 "this"キーワードを使うときは注意してください。毎回うまくいくわけではありません。

たとえば、TabActivityが2つのタブを持つホストとして構成されていて、各タブが別のアクティビティで、いずれかのタブ(アクティビティ)からダイアログを作成しようとしたときに "this"を使用すると、例外が発生します。ケースダイアログは、すべてをホストして表示されるホストアクティビティに接続する必要があります。 (あなたは最も目に見える親アクティビティのコンテキストを言うことができます)

私はどの文書からでもこの情報を見つけようとしませんでしたが試してみました。これは、強い経歴のない私の解決策です。もっとよく知られている人なら、遠慮なくコメントしてください。

5
Engin OZTURK

フラグメントを使用していてAlertDialog / Toastメッセージを使用している場合は、contextパラメーターにgetActivity()を使用してください。

私のために働きました。

乾杯!

5
curlyreggie

将来の読者にとって、これは助けになるでしょう:

public void show() {
    if(mContext instanceof Activity) {
        Activity activity = (Activity) mContext;
        if (!activity.isFinishing() && !activity.isDestroyed()) {
            dialog.show();
        }
    }
}

メインのUIスレッドではないスレッドからダイアログを表示しようとしている場合も同様に発生する可能性があります。

その場合はrunOnUiThread()を使用してください。

2
Erwan

New getParent()のような文脈の引数の場所でAlertDialog.Builder(getParent());を試してください。

2
Priyank Joshi

あるいは、次のようにDialogを作成することもできます。

final Dialog dialog = new Dialog(new ContextThemeWrapper(
            this, R.style.MyThemeDialog));
2
Martin Koubek

私の場合は、

this.getContext();
2
theWalker

APIを見て取った後、あなたは漏洩を防止するためのリターン方法で)あなたはフラグメントにいる場合は、強制的に(dialog.dismissでそれをクリーンアップダイアログをあなたの活動やgetActivityを渡すことができます。

それが明示的に私が知っているどこにも記載されていないが、あなただけでこれを行うにはOnClickHandlersでダイアログをバック渡されるようです。

1
G_V

私のアプリケーションで同じエラーを解決した方法は次のとおりです。
ダイアログの作成後に次の行を追加します。

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  

コンテキストを取得する必要はありません。これは、現在のポップアップダイアログの上に別のダイアログをポップアップする場合に特に便利です。または、コンテキストを取得するのが便利でない場合。

これがアプリの開発に役立つことを願っています。

デビッド

0
us_david

Dialogがアダプターで作成している場合:

アクティビティをアダプタコンストラクタに渡します。

adapter = new MyAdapter(getActivity(),data);

アダプターで受け取る:

 public MyAdapter(Activity activity, List<Data> dataList){
       this.activity = activity;
    }

ビルダーで使用できるようになりました

            AlertDialog.Builder alert = new AlertDialog.Builder(activity);
0
josedlujan