このエラーとは何ですか、そしてなぜそれが起こりますか?
05-17 18:24:57.069: ERROR/WindowManager(18850): Activity com.mypkg.myP has leaked window com.Android.internal.policy.impl.PhoneWindow$DecorView@44c46ff0 that was originally added here
05-17 18:24:57.069: ERROR/WindowManager(18850): Android.view.WindowLeaked: Activity ccom.mypkg.myP has leaked window com.Android.internal.policy.impl.PhoneWindow$DecorView@44c46ff0 that was originally added here
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.view.ViewRoot.<init>(ViewRoot.Java:231)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.view.WindowManagerImpl.addView(WindowManagerImpl.Java:148)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.view.WindowManagerImpl.addView(WindowManagerImpl.Java:91)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.view.Window$LocalWindowManager.addView(Window.Java:424)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.app.Dialog.show(Dialog.Java:239)
05-17 18:24:57.069: ERROR/WindowManager(18850): at com.mypkg.myP$PreparePairingLinkageData.onPreExecute(viewP.Java:183)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.os.AsyncTask.execute(AsyncTask.Java:391)
05-17 18:24:57.069: ERROR/WindowManager(18850): at com.mypkg.myP.onCreate(viewP.Java:94)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.app.Instrumentation.callActivityOnCreate(Instrumentation.Java:1047)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.app.ActivityThread.performLaunchActivity(ActivityThread.Java:2544)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.app.ActivityThread.handleLaunchActivity(ActivityThread.Java:2621)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.app.ActivityThread.access$2200(ActivityThread.Java:126)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.app.ActivityThread$H.handleMessage(ActivityThread.Java:1932)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.os.Handler.dispatchMessage(Handler.Java:99)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.os.Looper.loop(Looper.Java:123)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Android.app.ActivityThread.main(ActivityThread.Java:4595)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Java.lang.reflect.Method.invokeNative(Native Method)
05-17 18:24:57.069: ERROR/WindowManager(18850): at Java.lang.reflect.Method.invoke(Method.Java:521)
05-17 18:24:57.069: ERROR/WindowManager(18850): at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:860)
05-17 18:24:57.069: ERROR/WindowManager(18850): at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:618)
05-17 18:24:57.069: ERROR/WindowManager(18850): at dalvik.system.NativeStart.main(Native Method)
アクティビティを終了した後にダイアログを表示しようとしています。
[編集]
この質問は、Google for Android開発者向けのトップ検索の1つです。そのため、コメントから重要な点をいくつか追加します。これは、今後の調査担当者にとって、コメントを深く理解することなく役立つ場合があります。
答え1 :
アクティビティを終了した後にダイアログを表示しようとしています。
答え2
このエラーは状況によっては多少誤解を招く可能性があります(答えはまだ完全に正確です)。つまり、私の場合はAsyncTaskで未処理の例外がスローされ、Activityがシャットダウンし、次にopen progressdialogがこの例外を引き起こしました。 「本当の」例外は、ログの中で少し早かったです。
答え3
アクティビティを終了する前に作成したDialogインスタンスでdismiss()を呼び出します。 onPause()またはonDestroy()で
解決策はDialog
を終了する前にviewP.Java:183
で作成したActivity
でdismiss()
を呼び出すことです。 onPause()
で。 Window
を終了する前に、すべてのDialog
sおよびActivity
sを閉じてください。
AsyncTask
を使用している場合は、おそらくそのログメッセージが誤って表示される可能性があります。ログを調べてみると、おそらくAsyncTask
のdoInBackground()
メソッドに別のエラーがある可能性があります。これは現在のActivity
を爆発させることになります。したがって、AsyncTask
が戻ってきたら、あとはそれがわかります。他の何人かのユーザーはすでにここでそれを説明しました:-)
私は誤ってAlertDialog
に対してhide()
の代わりにdismiss()
を呼び出すことでこのエラーを引き起こしました。
Switchステートメントでbreak callステートメントを見逃した場合、(たとえば)AlertDialog
を表示した後に誤ってfinish()
を呼び出すことによって、単純な/ダムなミスによってこの例外を受け取ることができます。
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.new_button:
openMyAlertDialog();
break; <-- If you forget this the finish() method below
will be called while the dialog is showing!
case R.id.exit_button:
finish();
break;
}
}
finish()
メソッドはActivity
を閉じますが、AlertDialog
はまだ表示されています。
つまり、スレッド化の問題や複雑なコーディングなどを探してコードをじっと見つめているときに、ツリーの森を見失ってはいけません。時にはそれはちょうど単純なもので、欠けているbreakステートメントのように愚かなことがあります。 :)
この問題は、アクティビティを終了した後にダイアログを表示しようとしたときに発生します。
次のコードを書き留めることで、この問題を解決しました。
@Override
public void onDestroy(){
super.onDestroy();
if ( progressDialog!=null && progressDialog.isShowing() ){
progressDialog.cancel();
}
}
基本的に、どのクラスからprogressDialogを起動したかによって、onDestroyメソッドをオーバーライドしてこの方法を実行します。 「アクティビティがウィンドウからリークした」問題を解決しました。
この質問に対する答えはすべて正しかったのですが、なぜ私が実際に理解しているのかを少し分かりにくいものにしました。約2時間遊んだ後、このエラーの理由(私の場合)が私を襲った。
他の答えを読んで、has X has leaked window DecorView@d9e6131[]
エラーが発生したのは、アプリを閉じたときにダイアログが開いていたことを意味しています。しかし、なぜ?
ダイアログが開いている間に他の理由でアプリがクラッシュした可能性があります
これは、コードにバグがあるためにアプリケーションが閉じられることにつながります。そのため、他のエラーが原因でアプリケーションが閉じられると同時にダイアログが開いたままになります。
だから、あなたの論理を見てください。最初のエラーを解決してから、2番目のエラーが自分自身を解決します
DOMINOSのように、あるエラーが別のエラーを引き起こし、それが別のエラーを引き起こします。
私は最近同じ問題に直面しました。
この問題の背後にある理由は、ダイアログが閉じられる前にアクティビティが閉じられていることです。上記が発生するのにはさまざまな理由があります。上記の記事に記載されているものも正しいです。
私は状況に入りました、なぜならスレッドの中で、私は例外を投げていた関数を呼んでいたからです。そのため、ウィンドウは却下されていたため、例外です。
これは助けになるかもしれません。
if (! isFinishing()) {
dialog.show();
}
アクティビティが破棄されたらダイアログを閉じる
@Override
protected void onDestroy()
{
super.onDestroy();
if (pDialog!=null && pDialog.isShowing()){
pDialog.dismiss();
}
}
私は同じあいまいなエラーメッセージを持っていたし、なぜかわからなかった。前の答えからの手がかりを考えて、私はmDialog.finish()への私の非GUI呼び出しをmDialog.dismiss()に変更し、そしてエラーは消えた。これは私のウィジェットの振る舞いには影響しませんでしたが、それは混乱を招き、重要なメモリリークのフラグを立てていた可能性があります。
私は自分のビデオプレーヤーアプリケーションでこれらのログを取得していました。これらのメッセージは、ビデオプレーヤーが閉じている間にスローされました。興味深いことに、私はこれらのログを数回の実行でランダムに取得していました。また、私のアプリケーションはどのprogressdialog
にも関わっていません。最後に、私は以下の実装でこの問題を回避しました。
@Override
protected void onPause()
{
Log.v("MediaVideo", "onPause");
super.onPause();
this.mVideoView.pause();
this.mVideoView.setVisibility(View.GONE);
}
@Override
protected void onDestroy()
{
Log.v("MediaVideo", "onDestroy");
super.onDestroy();
}
@Override
protected void onResume()
{
Log.v("MediaVideo", "onResume");
super.onResume();
this.mVideoView.resume();
}
mVideoView.pause()
を呼び出し、OnPause
をvisibility
に設定してGONE
をオーバーライドします。こうすれば私は "Activity has leaked window
"ログエラー問題を解決できます。
私は同じ問題を抱えていてこのページを見つけました、そして私の状況が異なっていた間、私は警告ボックスを定義する前にfinish
ブロックからif
を呼び出しました。
そのため、単にdismiss
を呼び出しても(まだ行われていないので)うまくいきませんが、 Alex Volovoy's answerを読んでそれを実現する警告ボックスであることに気付いた後に。私はそのif
ブロックの中の終わりの直後にreturnステートメントを追加しようとしました、そしてそれは問題を修正しました。
私はあなたが終了と呼ばれればそれがすべてを止めて、そしてすぐそこで終えたと思った、しかしそれはそうではない。それはそれが終わったところでそれが終わったコードのブロックの終わりまで行くようです。
そのため、コードを実行する前に終了することがある状況を実装したい場合は、終了直後にreturn文を入力するか、継続して終了後に終了が呼び出されたように動作します。あなたがそれを呼び出した場所ではないコードのブロック。それが、私がそれらすべての奇妙なエラーを起こしていた理由です。
private picked(File aDirectory){
if(aDirectory.length()==0){
setResult(RESULT_CANCELED, new Intent());
finish();
return;
}
AlertDialog.Builder alert= new AlertDialog.Builder(this); // Start dialog builder
alert
.setTitle("Question")
.setMessage("Do you want to open that file?"+aDirectory.getName());
alert
.setPositiveButton("OK", okButtonListener)
.setNegativeButton("Cancel", cancelButtonListener);
alert.show();
}
そこにfinishを呼び出した直後にreturnを入れないと、alert.show();
の後にreturnを呼び出したのと同じように動作するため、ダイアログを表示した直後に終了することでウィンドウがリークされていると言えます。そうではありません、それはまだだと思います。
これはfinishコマンドが異なる動作をしていることを示しているので、ここにこれを追加したいと思いました。それから私はそれをしたと思っていました。
これは質問に対する答えではありませんが、トピックに関連しています。
アクティビティがマニフェストで属性を定義している場合
Android:noHistory="true"
onPause()を実行した後、アクティビティのコンテキストは失われます。したがって、すべてのビューで this コンテキストを使用すると、このエラーが発生する可能性があります。
アラートを表示しようとするだけでなく、アクティビティの特定のインスタンスを終了して新しいアクティビティ/サービスを開始しようとしたり、停止しようとしたときにもアラートを呼び出すことができます。
例:
OldActivity instance;
oncreate() {
instance=this;
}
instance.finish();
instance.startActivity(new Intent(ACTION_MAIN).setClass(instance, NewActivity.class));
このコードを試してください:
public class Sample extends Activity(){
@Override
public void onCreate(Bundle instance){
}
@Override
public void onStop() {
super.onStop();
progressdialog.dismiss(); // try this
}
}
ProgressDialogがまだ表示されていたときにアクティビティを終了した問題がありました。
そのため、最初にダイアログを非表示にしてからアクティビティを終了します。
これは私がProgressDialog
でAsyncTask
を使っているときに私に起こりました。実は私はonPostExecute
でhide()
メソッドを使っています。 @Alex Volovoyの回答に基づき、onPostExecuteでそれを削除するには、dismiss()
をProgressDialog
とともに使用する必要があります。
progressDialog.hide(); // Don't use it, it gives error
progressDialog.dismiss(); // Use it
Activity
が事実上finished
になった後にアラートを表示しようとすると、「Activity has leaked window that was originally added...
」エラーが発生します。
2つの選択肢があります。
dialog
でdismiss()
を呼び出します。dialog
を別のスレッドに入れて、そのthread
上で実行します(現在のactivity
とは無関係)。doInBackground()
関数にエラーがあり、このコードがある場合、これがあります。
最後にダイアログを追加してみてください。最初にdoInBackground()
関数をチェックして修正する
protected void onPreExecute() {
super.onPreExecute();
pDialog = new ProgressDialog(CreateAccount.this);
pDialog.setMessage("Creating Product..");
pDialog.setIndeterminate(false);
pDialog.setCancelable(true);
pDialog.show();
}
protected String doInBackground(String...args) {
ERROR CAN BE IS HERE
}
protected void onPostExecute(String file_url) {
// dismiss the dialog once done
pDialog.dismiss();
通常、この問題は進行状況ダイアログが原因で発生します。アクティビティに次の方法のいずれかを使用してこれを解決できます。
// 1):
@Override
protected void onPause() {
super.onPause();
if ( yourProgressDialog!=null && yourProgressDialog.isShowing() )
{
yourProgressDialog.cancel();
}
}
// 2) :
@Override
protected void onDestroy() {
super.onDestroy();
if ( yourProgressDialog!=null && yourProgressDialog.isShowing()
{
yourProgressDialog.cancel();
}
}
Progressdialog
のonPreExecute
メソッドにAsyncTask
オブジェクトを作成する必要があり、dismiss
メソッドにonPostExecute
オブジェクトを作成する必要があります。
最善の解決策は、try catchにダイアログを追加し、例外が発生したときにダイアログを閉じることです
以下のコードを使用してください
try {
dialog.show();
} catch (Exception e) {
dialog.dismiss();
}
私の場合は、Androidマニフェストファイルに許可を含めるのを忘れたためです。
どうやって見つけたの? @Bobbyが受け入れられた回答の下にあるコメントで述べているのと同じように、ログまでさらにスクロールすると、例外をスローした最初の理由またはイベントが表示されます。どうやら、「アクティビティが最初に追加されたウィンドウをリークしました」というメッセージは、最初の例外が何であっても、その結果生じた例外にすぎません。
以下のコードを試してください、それはあなたが進行状況ダイアログを閉じるとそれはそのインスタンスが利用可能かどうかを確認しますいつでも動作します。
try {
if (null != progressDialog && progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
} catch (Exception e) {
e.printStackTrace();
}
ウィンドウリーク例外には2つの理由があります。
1)アクティビティコンテキストが存在しないときにダイアログを表示するには、これを解決するために、アクティビティが存在することが確実である場合にのみダイアログを表示する必要があります。
if(getActivity()!= null && !getActivity().isFinishing()){
Dialog.show();
}
2)このコードを使用して解決するために、ダイアログを適切に閉じないでください。
@Override
public void onDestroy(){
super.onDestroy();
if ( Dialog!=null && Dialog.isShowing() ){
Dialog.dismiss();
}
}
progressbar
またはprogressDialog
を表示する前に、これを最善の方法で解決します。
if (getApplicationContext().getWindow().getDecorView().isShown()) {
//Show Your Progress Dialog
}
コード内のどこかで発生した例外のために、アクティビティが突然終了しないようにしてください。一般に、アクティビティがdoinBackgroundメソッドで強制終了に直面し、次にasynctaskがonPostexecuteメソッドに戻ると、非同期タスクで発生します。
私によると問題は、アクティビティが終了した直後にダイアログを呼び出そうとしているということです。そのため私ができることは、Handlerを使用してある程度の遅延を与えることです。
Handler handler=new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
dialog.show();
//or
dialog.dismiss();
}
},100);
if (mActivity != null && !mActivity.isFinishing() && mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
}
バックグラウンドスレッドからトーストを表示しようとしたときにこのエラーが発生しました。 UIスレッドでUI関連のコードを実行することで解決しました
私は同じ種類の問題を抱えています。エラーはDialog
ではなくEditText
にありました。私はEdittext
の中でAssynctask
の値を変更しようとしていました。私が解決できる唯一の方法は、新しいrunnable
を作成することでした。
runOnUiThread(new Runnable(){
@Override
public void run() {
...
}
});
私はこれのための別の解決策があります、そしてそれがあなたに有効であるように思われるかどうか知りたいです:onDestroyで却下するのではなく、それは主要な解決策であるように、私はProgressDialogを拡張します...
public class MyProgressDialog extends ProgressDialog {
private boolean isDismissed;
public MyProgressDialog(Context context) {
super(context);
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
dismiss();
}
@Override
public void dismiss() {
if (isDismissed) {
return;
}
try {
super.dismiss();
} catch (IllegalArgumentException e) {
// ignore
}
isDismissed = true;
}
進行状況ダイアログをメンバーとして保持する必要はなく、ただ発砲(表示)して忘れるので、これはAFAICの方が望ましいです。
必ずthis.dialog.showを呼び出してください。 (アクティビティ)
私はまたサルテストを実行するときにWindowLeaked問題に遭遇します。logcatは以下です。
Android.support.v7.app.AppCompatDelegateImplV7$ListMenuDecorView@4334fd40 that was originally added here
Android.view.WindowLeaked: Activity com.myapp.MyActivity has leaked window Android.support.v7.app.AppCompatDelegateImplV7$ListMenuDecorView@4334fd40 that was originally added here
at Android.view.ViewRootImpl.<init>(ViewRootImpl.Java:409)
at Android.view.WindowManagerImpl.addView(WindowManagerImpl.Java:312)
at Android.view.WindowManagerImpl.addView(WindowManagerImpl.Java:224)
at Android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.Java:149)
at Android.view.Window$LocalWindowManager.addView(Window.Java:554)
at Android.support.v7.app.AppCompatDelegateImplV7.openPanel(AppCompatDelegateImplV7.Java:1150)
at Android.support.v7.app.AppCompatDelegateImplV7.onKeyUpPanel(AppCompatDelegateImplV7.Java:1469)
at Android.support.v7.app.AppCompatDelegateImplV7.onKeyUp(AppCompatDelegateImplV7.Java:919)
at Android.support.v7.app.AppCompatDelegateImplV7.dispatchKeyEvent(AppCompatDelegateImplV7.Java:913)
at Android.support.v7.app.AppCompatDelegateImplBase$AppCompatWindowCallbackBase.dispatchKeyEvent(AppCompatDelegateImplBase.Java:241)
at com.Android.internal.policy.impl.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.Java:2009)
at Android.view.ViewRootImpl.deliverKeyEventPostIme(ViewRootImpl.Java:3929)
at Android.view.ViewRootImpl.deliverKeyEvent(ViewRootImpl.Java:3863)
at Android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.Java:3420)
at Android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.Java:4528)
at Android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.Java:4506)
at Android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.Java:4610)
at Android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.Java:171)
at Android.os.MessageQueue.nativePollOnce(Native Method)
at Android.os.MessageQueue.next(MessageQueue.Java:125)
at Android.os.Looper.loop(Looper.Java:124)
at Android.app.ActivityThread.main(ActivityThread.Java:4898)
at Java.lang.reflect.Method.invokeNative(Native Method)
at Java.lang.reflect.Method.invoke(Method.Java:511)
at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:1008)
at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:775)
at dalvik.system.NativeStart.main(Native Method)
私のアクティビティはAppCompatActivityです。そして、アクティビティの下のコードでそれを作り直しました。
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
// added by sunhang : intercept menu key to resove a WindowLeaked error in monkey-test.
if (event.getKeyCode() == KeyEvent.KEYCODE_MENU) {
return true;
}
return super.dispatchKeyEvent(event);
}
LiveDataを扱っている場合は、liveData.value = someValue
を使用する代わりに値を更新するときにliveData.postValue(someValue)
を実行してください。
私はVideo PlayerのonErrorダイアログを使用していましたが、代わりに頭がおかしくなりました(これらすべての解決策を試してみました)。
DialogFragment
http://developer.Android.com/reference/Android/app/DialogFragment.html を選択しました。
内部のDialogFragment
クラスでビルダーの作成を返すことができます。単にonCreateDialog
をオーバーライドするだけです。
たぶんあなたはdialog.findViewById
の代わりにfindViewById
をactivityに使っていて、その後OnClickListener
インスタンスにnull
をセットしていて、それがおそらく元のエラーを引き起こしたのかもしれません。
私もしばらくの間この問題に直面していましたが、私の場合はdialog
が原因ではなくActionMode
が原因ではないことに気付きました。 ActionMode
が開いているときにアクティビティを終了しようとすると、この問題が発生します。あなたのアクティビティのonPause
でアクションモードを終了します。
private ActionMode actionMode;
@Override
public void onActionModeStarted(ActionMode mode) {
super.onActionModeStarted(mode);
actionMode = mode;
}
@Override
protected void onPause() {
super.onPause();
if (actionMode != null) actionMode.finish();
}