私の活動は、パラメータとしてコンテキストを必要とするAlertDialogを作成しようとしています。私が使用する場合、これは予想通りに動作します。
AlertDialog.Builder builder = new AlertDialog.Builder(this);
しかし、画面が回転するような単純な操作でもActivityが破棄されて再作成されると、メモリリークが発生する可能性があるため、 "this"をコンテキストとして使用するのは嫌です。 Android開発者のブログの 関連の投稿から :
コンテキスト関連のメモリリークを回避する簡単な方法が2つあります。最も明白なものはそれ自身の範囲の外で文脈をエスケープすることを避けることです。上記の例では静的参照の場合を示しましたが、内部クラスとその外部クラスへの暗黙の参照も同様に危険です。 2番目の解決策はアプリケーションコンテキストを使用することです。あなたのアプリケーションが生きていて活動のライフサイクルに依存しない限り、このコンテキストは生き続けるでしょう。コンテキストを必要とする長寿命のオブジェクトを維持する予定の場合は、アプリケーションオブジェクトを覚えておいてください。 Context.getApplicationContext()またはActivity.getApplication()を呼び出すことで簡単に取得できます。
しかしAlertDialog()
の場合、例外としてスローされるので、getApplicationContext()
もgetApplication()
もコンテキストとしては受け入れられません。
「ウィンドウを追加できません - トークンnullはアプリケーション用ではありません」
それで、これは本当に "バグ"と見なされるべきです、なぜなら私たちは公式にActivity.getApplication()
を使うように勧められていますが、それでも宣伝どおりに機能しないのですか?
ジム
getApplicationContext()
の代わりに、単にActivityName.this
を使ってください。
this
を使ってもうまくいきませんでしたが、MyActivityName.this
はうまくいきました。これがthis
を動作させることができなかった人に役立つことを願っています。
引き続きgetApplicationContext()
を使用することができますが、使用する前に、このフラグを追加する必要があります:dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)
、そしてエラーが表示されません。
マニフェストに次の権限を追加してください。
<uses-permission Android:name="Android.permission.SYSTEM_ALERT_WINDOW" />
あなたの対話は「コンテキストを必要とする長命のオブジェクト」であってはなりません。ドキュメントは紛らわしいです。基本的にあなたが何かのようなことをするならば:
static Dialog sDialog;
( static に注意してください)
それからどこかの活動であなたがした
sDialog = new Dialog(this);
ローテーションなどで元のアクティビティがリークして、アクティビティが破壊される可能性があります。 (onDestroyでクリーンアップしない限り、ただしその場合はDialogオブジェクトを静的にはしないでしょう)
データ構造によっては、データ構造を静的にしてアプリケーションのコンテキストに基づかせるのが理にかなっていますが、一般的にダイアログのようなUI関連のものには意味がありません。だからこのようなもの:
Dialog mDialog;
...
mDialog = new Dialog(this);
MDialogは静的ではないので、mDialogはアクティビティから解放されるので、問題はなく、アクティビティをリークしてはいけません。
「... 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"(または他の参照)によって無期限に参照される原因となる論理エラーについてコードを確認してください。チェーンの参照も確認してください。これは、メモリ使用量を分析し、そのような厄介なメモリリークを見つけるのに役立つツールです。
フラグメントで表示されたカスタムアダプタのコンストラクタを通してコンテキストを送信する必要があり、getApplicationContext()でこの問題がありました。私はそれを解決しました:
フラグメントのonCreate
コールバックのthis.getActivity().getWindow().getContext()
。
アクティビティ だけに使用:
MyActivity.this
の中に:
getActivity();
ダイアログボックスを表示しているボタンをクリックするとActivity
に
Dialog dialog = new Dialog(MyActivity.this);
私のために働きました。
ちょっとしたハック:あなたはGCによってあなたの活動を破壊することを防ぐことができます(そうするべきではありませんが、状況によっては助けになることができます。不要になったらcontextForDialog
をnull
に設定することを忘れないでください):
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();
}
...
}
フラグメントを使用しており、AlertDialog/Toastメッセージを使用している場合は、コンテキストパラメータでgetActivity()を使用します。
このような
ProgressDialog pdialog;
pdialog = new ProgressDialog(getActivity());
pdialog.setCancelable(true);
pdialog.setMessage("Loading ....");
pdialog.show();
applicationContext
やbaseContext
の代わりにthis@YourActivity
を渡すべきです
私はフラグメントでProgressDialog
を使用していて、コンストラクタパラメータとしてgetActivity().getApplicationContext()
を渡すことでこのエラーを得ていました。 getActivity().getBaseContext()
に変更してもうまくいきませんでした。
私のために働いた解決策はgetActivity()
を渡すことでした。すなわち.
progressDialog = new ProgressDialog(getActivity());
追加
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
そして
マニフェストの"Android.permission.SYSTEM_ALERT_WINDOW"/>
それは今私のために働きます。アプリケーションを閉じて開いた後も、そのときにエラーが発生しました。
あなたが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);
MyDialog md = new MyDialog(MyActivity.this.getParent());
を使う
ダイアログの下にあるアクティビティのコンテキストを使用するようにしてください。しかし、 "this"キーワードを使うときは注意してください。毎回うまくいくわけではありません。
たとえば、TabActivityが2つのタブを持つホストとして構成されていて、各タブが別のアクティビティで、いずれかのタブ(アクティビティ)からダイアログを作成しようとしたときに "this"を使用すると、例外が発生します。ケースダイアログは、すべてをホストして表示されるホストアクティビティに接続する必要があります。 (あなたは最も目に見える親アクティビティのコンテキストを言うことができます)
私はどの文書からでもこの情報を見つけようとしませんでしたが試してみました。これは、強い経歴のない私の解決策です。もっとよく知られている人なら、遠慮なくコメントしてください。
フラグメントを使用していてAlertDialog / Toast
メッセージを使用している場合は、contextパラメーターにgetActivity()
を使用してください。
私のために働きました。
乾杯!
将来の読者にとって、これは助けになるでしょう:
public void show() {
if(mContext instanceof Activity) {
Activity activity = (Activity) mContext;
if (!activity.isFinishing() && !activity.isDestroyed()) {
dialog.show();
}
}
}
メインのUIスレッドではないスレッドからダイアログを表示しようとしている場合も同様に発生する可能性があります。
その場合はrunOnUiThread()
を使用してください。
New getParent()
のような文脈の引数の場所でAlertDialog.Builder(getParent());
を試してください。
あるいは、次のようにDialogを作成することもできます。
final Dialog dialog = new Dialog(new ContextThemeWrapper(
this, R.style.MyThemeDialog));
私の場合は、
this.getContext();
APIを見て取った後、あなたは漏洩を防止するためのリターン方法で)あなたはフラグメントにいる場合は、強制的に(dialog.dismissでそれをクリーンアップダイアログをあなたの活動やgetActivityを渡すことができます。
それが明示的に私が知っているどこにも記載されていないが、あなただけでこれを行うにはOnClickHandlersでダイアログをバック渡されるようです。
私のアプリケーションで同じエラーを解決した方法は次のとおりです。
ダイアログの作成後に次の行を追加します。
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
コンテキストを取得する必要はありません。これは、現在のポップアップダイアログの上に別のダイアログをポップアップする場合に特に便利です。または、コンテキストを取得するのが便利でない場合。
これがアプリの開発に役立つことを願っています。
デビッド
Dialogがアダプターで作成している場合:
アクティビティをアダプタコンストラクタに渡します。
adapter = new MyAdapter(getActivity(),data);
アダプターで受け取る:
public MyAdapter(Activity activity, List<Data> dataList){
this.activity = activity;
}
ビルダーで使用できるようになりました
AlertDialog.Builder alert = new AlertDialog.Builder(activity);