アクティビティは、最初に追加されたウィンドウをリークしました


1163

このエラーとは何ですか?なぜ発生するのですか?

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)

6
もう1つのクラシックは、向きが変わったときです。stackoverflow.com
questions

回答:


1561

アクティビティを終了した後にダイアログを表示しようとしています。

[編集]

この質問は、Android開発者にとってGoogleでのトップ検索の1つであるため、コメントから重要なポイントをいくつか追加します。これは、コメントの会話を深く掘り下げることなく、将来の調査者にとってより役立つ可能性があります。

回答1

アクティビティを終了した後にダイアログを表示しようとしています。

回答2

このエラーは、状況によっては少し誤解を招く可能性があります(ただし、答えは完全に正確です)。つまり、私の場合、未処理の例外がAsyncTaskでスローされ、アクティビティがシャットダウンし、進行中のダイアログが開いているため、この例外が発生しました。 「本当の」例外はログの少し早い段階でした

回答3

onPause()やonDestroy()などで、アクティビティを終了する前に作成したDialogインスタンスでdismiss()を呼び出します


2
@Override public void onStop(){if(dialog!= null){dialog.dismiss(); ダイアログ= null; }}
Md.Tarikul Islam 2017

14
8年経っても、これはまだ適切です。AlertDialogを表示しようとしたときにアクティビティが閉じられたため、例外が発生しました(そのため、回答2)。最終的に、アプリがシーンに「null」オブジェクトを追加していることはわかっていましたが(発生しなかったはずですが、実際には発生しました)、例外はありませんでした。代わりにウィンドウ」例外。
Neph

すべての開いているダイアログをスキャンして、onStop()でそれらをすべて閉じることは可能ですか?アイテムをクリックすると、ListViewにダイアログが生成されます。onStopから参照を取得する方法がわかりません。
Myoch

1
回答3が最善の解決策です。私のために大いに働いた。アレックス、風に感謝!
amit bansode

ダイアログをループで表示している場合の追加のヒントは、アクティビティの終了後にループが終了するようにする
Thecarisma

406

解決策は、たとえばで終了する前dismiss()に、Dialogで作成したを呼び出すことです。を離れる前に、すべてのS&を閉じる必要があります。viewP.java:183ActivityonPause()WindowDialogActivity


3
したがって、ユーザーが電話を回転させると、すべてのダイアログを閉じる必要がありますか?それは正しく聞こえません。
LarsH 2017

@LarsHご覧のとおり、私の回答は7年以上前に書かれたものであり、当時は間違いなく本当でした。私はもはやAndroidを使用していませんが、ドキュメントに表示されている内容に基づいて、それはまだ事実である可能性がありますが、Androidは(名前を付けるためにFragmentsを導入した)以来、長い道のりを歩んできました。
molnarm 2017年

108

を使用している場合AsyncTask、おそらくそのログメッセージは不正である可能性があります。ログを調べると、おそらくあなたののdoInBackground()メソッドにある別のエラーが見つかり、それが原因でAsyncTask現在のデータActivityが爆発的に増加しているため、AsyncTask戻ってきたら残りを知っています。他の何人かのユーザーはすでにここでそれを説明しました:-)


22
場合によっては、実際の例外を確認できないことがあります。実際の例外を見つけるには、progressDialog.show()をコメントアウトして、アプリをもう一度実行します。これで表示されます。
スタック

こんにちは!上記の@Stuckで述べたように、実際の例外も確認できません。ブレークポイントを使用して追跡したところdoInBackgroundAsyncTaskクラスのメソッド内でApplicationクラスの参照を使用していたが、次のようなAndroidManifestプロパティを使用してファイル内で宣言していないことがわかりました。使用する際の良い習慣は、常にメソッド内でアラートをインスタンス化し、それを閉じることを忘れないでください。android:nameandroid:name="my.package.MyApplicationClass"AsyncTaskonPreExecuteonPostExecute
GFPF 2018

66

このエラーは、のhide()代わりに誤って呼び出してトリガーしdismiss()ましたAlertDialog


4
まさに私に何が起こったのか。また、hide()を呼び出してからダイアログをnullに設定することも有効な代替手段ではありません。
Lucas Tulio 2013年

私はこれの背後にある問題を本当に知っているでしょう。しかし、dismiss()を呼び出すと役に立ちました!
Karoly、2017

59

switchステートメントのbreak callステートメントを見逃した場合、(たとえば)finish()を表示した後に誤って呼び出して、単純な/ばかげた間違いによってこの例外を取得できますAlertDialog...

   @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ステートメントと同じくらい単純で馬鹿げている場合もあります。:)


多かれ少なかれ正確に私の問題。終了ボタンのonClickではなく、ダイアログの作成後にonErrorでfinishを呼び出しました。
jbass 2017年

46

この質問への回答はすべて正解でしたが、実際に理由を理解するのに少し混乱しました。約2時間遊んだ後、このエラーの理由(私の場合)が私を襲いました:

他の回答を読んで、X has leaked window DecorView@d9e6131[]エラーがあることはアプリが閉じたときにダイアログが開いていたことをすでに知っています。しかし、なぜ?

ダイアログが開いている間にアプリが他の何らかの理由でクラッシュした可能性があります

これは、コード内のいくつかのバグのためにアプリを閉じることにつながり、他のエラーのためにアプリが閉じられると同時にダイアログが開いたままになります。

だから、あなたの論理を見てください。最初のエラーを解決すると、2番目のエラーが自動的に解決されますここに画像の説明を入力してください

あるエラーが別のエラーを引き起こし、それがDOMINOSのような別のエラーを引き起こします!


2
これは一つだけupvoteを持っていると信じて...または私達はハハハ、私はまた、あなたのドミノのアナロジーを気に入っプログラミングで本当に悪いことはできません
user2161301

最初のエラーを解決すると、2番目のエラーは発生しなくなります。この類推は私を助けました。
itabdullah

これは完全に正しくはありません。電話のローテーションのようなインスタンスも「アクティビティ」ローテーションを発生させる可能性があります。
Sreekanth Karumanaghat

36

この問題は、アクティビティを終了した後にダイアログを表示しようとすると発生します。

次のコードを書き留めて、この問題を解決しました。

@Override
public void onDestroy(){
    super.onDestroy();
    if ( progressDialog!=null && progressDialog.isShowing() ){
        progressDialog.cancel();
    }
}

基本的には、どのクラスからProgressDialogを開始し、onDestroyメソッドをオーバーライドして、このようにします。「アクティビティがウィンドウをリークしました」の問題を解決しました。


onDestroyの呼び出しは保証されていません。そのコードをonPauseまたはonStopに入れる方が良い
Amruta-Pani

19

最近同じ問題に直面しました。

この問題の背後にある理由は、ダイアログが閉じられる前にアクティビティが閉じられるためです。上記が発生する理由はさまざまです。上記の投稿に記載されているものも正しいです。

スレッドで、例外をスローしていた関数を呼び出していたため、状況になりました。そのため、ウィンドウが却下されていたため、例外が発生しました。


16

アクティビティが破棄されたときにダイアログを閉じます

@Override
protected void onDestroy()
{
    super.onDestroy();
    if (pDialog!=null && pDialog.isShowing()){
        pDialog.dismiss();
    }
}

pDialogがnullの場合、nullダイアログの状態を照会するときにエラーがスローされます
Jonathan Dunn

1
いいえ、最初のブール値がfalseの場合、Javaは2番目のブール値を処理しないため、@ JonDunnは行われません
matdev

13

これは役に立ちます。

if (! isFinishing()) {

    dialog.show();

    }

2
何百もの類似した回答の中に、ウィンドウが存在するかどうかを確認する方法を示す人はいません。それで、あなたはそれを行う方法を見つける時間を節約できます。ありがとう。
kolyaseg

11

同じ不明瞭なエラーメッセージが表示され、その理由がわかりませんでした。以前の回答からの手がかりを与えられて、私はmDialog.finish()への私の非GUI呼び出しをmDialog.dismiss()に変更し、エラーは消えました。これは私のウィジェットの動作には影響しませんでしたが、それは当惑し、重要なメモリリークのフラグを立てていた可能性があります。


finish()を呼び出す前にmDialog.hide()を実行していたことに注意してください。それをmDialog.dismiss()に変更するとうまくいきました。
2011

11

ビデオプレーヤーアプリケーションでこれらのログを取得していました。これらのメッセージは、ビデオプレーヤーが閉じているときにスローされました。興味深いことに、私はこれらのログを数回の実行で一度ランダムに取得していたものです。また、私のアプリケーションは何にも関与していません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();
}

OnPausewith call to mVideoView.pause()およびset visibilityto をオーバーライドしGONEます。このようにして、 " Activity has leaked window"ログエラーの問題を解決できました。


私も同じ問題に直面しています。これらのコード行をコードに追加しましたが、機能せず、同じエラー「最初に追加されたandroid.view.WindowLeaked」が表示され、ビデオも再生されず、「ビデオを再生できません」と表示されます
User42590

10

私は同じ問題を抱えていてこのページを見つけました、そして私の状況は異なっていましたが、警告ボックスを定義する前にブロックfinishから呼び出しましたif

だから、単純に呼び出すdismiss仕事ではないでしょう(それはまだなされていないもの)が、読んだ後、アレックスVolovoyの答えをして実現し、それを引き起こして警告ボックスでした。そのifブロック内の終了直後にreturnステートメントを追加しようとしましたが、これで問題が修正されました。

私は、finishを呼び出すと、すべてが停止し、そこですぐに終了したと思いましたが、それはしませんでした。それが入っているコードのブロックの最後に行き、終了するようです。

したがって、いくつかのコードを実行する前に終了することがある状況を実装する場合は、終了直後に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();ので、それはダイアログを表示させた直後に完了によってウィンドウがリークされていると言えます。そうではない、それはまだそうだと思います。

これは、finishコマンドの動作が異なることを示しているので、ここに追加すると思ったのですが、実際にそうしたのです。これを発見する前に、私と同じように考えている人が他にいると思います。


7

これは質問に対する答えではありませんが、トピックに関連しています。

アクティビティがマニフェストで属性を定義している場合

 android:noHistory="true"

その後、onPause()を実行すると、アクティビティのコンテキストが失われます。したがって、すべてのビューがこのコンテキストを使用しいると、このエラーが発生する可能性があります。


あなたは何のために類似した関連することができprogessdialog.show()..とprogressdialog.hide()asynctask同じ活動の代わりにonPause()からのactivity?? 私の問題を見て... stackoverflow.com/questions/39332880/...
Bhuro

1
その完璧な動作:android:noHistory = "true"
Shohel Rana

6

アラートを表示しようとするだけでなく、アクティビティの特定のインスタンスを終了し、新しいアクティビティ/サービスを開始または停止しようとしたときにも呼び出されます。

例:

OldActivity instance;

    oncreate() {
       instance=this;
    }
    instance.finish();
    instance.startActivity(new Intent(ACTION_MAIN).setClass(instance, NewActivity.class));

6

通常、この問題は進行状況ダイアログが原因で発生します。アクティビティで次のいずれかの方法を使用してこれを解決できます。

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

5

ProgressDialogがまだ表示されているときにアクティビティを終了したときに問題が発生しました。

したがって、まずダイアログを非表示にしてから、アクティビティを終了します。


5

このコードを試してください:

public class Sample extends Activity(){
@Override
 public void onCreate(Bundle instance){

}
 @Override
    public void onStop() {
        super.onStop();
      progressdialog.dismiss(); // try this
    }

}

progressdialog.dismiss();これにより、NullPointerExceptionが作成される可能性があります。
tpk

5

これは、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();

5

これは、で使用しているときに起こりProgressDialogましたAsyncTask。実際、私はのhide()メソッドを使用していonPostExecuteます。@Alex Volovoyの回答に基づいて、onPostExecuteでそれを削除するためにdismiss()with ProgressDialogを使用する必要があります。

progressDialog.hide(); // Don't use it, it gives error

progressDialog.dismiss(); // Use it

これは実際には完全な答えではありません。ダイアログをリークする方法は2つあります。1)がありAsyncTask、を表示している場合DialogActivity呼び出しを行う何かが発生しますonPause()(おそらくリスナーのようなAsyncTask自体のロジックで、それがリークします。2)上記のように、それでDialog作成されたActivity Contextは決してありません解雇され、Activity移動します。
トリックノロジー2017年

5

Activity has leaked window that was originally added...あなたは後に警告を表示しようとすると」エラーが発生したActivity事実ですfinished

AFAIKには2つのオプションがあります。

  1. アラートのログインを再考:コールdismiss()のをdialog前に実際にあなたの活動を終了します。
  2. dialog別のスレッドに入れ、そのスレッドで実行しますthread(現在のとは無関係activity)。

5

AlertDialogを閉じたいが、アクティビティ内でそれへの参照保持したくない場合の解決策次に示します。

ソリューションでは、プロジェクトにandroidx.lifecycle依存関係が必要です(コメントの時点では、これは一般的な要件だと思います)

これにより、ダイアログの終了を外部オブジェクト(オブザーバー)に委任することができます。アクティビティが終了すると自動的にサブスクライブ解除されるため、ダイアログを破棄する必要はもうありません。(ここに証明があります:https : //github.com/googlecodelabs/android-lifecycles/issues/5)。

したがって、オブザーバーはダイアログへの参照を保持し、アクティビティはオブザーバーへの参照を保持します。「onPause」が発生した場合-オブザーバーがダイアログを閉じ、「onDestroy」が発生した場合-アクティビティがオブザーバーを削除するため、リークは発生しません(少なくとも、logcatにエラーが表示されなくなります)

// observer
class DialogDismissLifecycleObserver( private var dialog: AlertDialog? ) : LifecycleObserver {
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun onPause() {
        dialog?.dismiss()
        dialog = null
    }
}
// activity code
private fun showDialog() {
        if( isDestroyed || isFinishing ) return
        val dialog = AlertDialog
            .Builder(this, R.style.DialogTheme)
            // dialog setup skipped
            .create()
        lifecycle.addObserver( DialogDismissLifecycleObserver( dialog ) )
        dialog.show()
}

4

ウィンドウリーク例外には2つの理由があります。

1)アクティビティコンテキストが存在しない場合にダイアログを表示します。これを解決するには、アクティビティが存在することを確信している場合にのみダイアログを表示する必要があります。

if(getActivity()!= null && !getActivity().isFinishing()){
        Dialog.show();
}

2)このコードを使用して解決するために、ダイアログを適切に閉じないでください:

@Override
public void onDestroy(){
    super.onDestroy();
    if ( Dialog!=null && Dialog.isShowing() ){
        Dialog.dismiss();
}
}

4

あなたは確認する必要がありますProgressdialog内のオブジェクトonPreExecuteのメソッドをAsyncTask、あなたがすべきdismissでそれをonPostExecuteする方法。


4

最良の解決策は、例外が発生したときにダイアログを追加してトライキャッチし、ダイアログを閉じることです

以下のコードを使用するだけ

 try {
        dialog.show();
    } catch (Exception e) {
        dialog.dismiss();
    }

3
が呼び出された後にダイアログがnullになることはありませんか?、私dialog.dismiss()もエラーを生成すると思います
Ashu Kumar

3

私の場合、その理由は、Androidマニフェストファイルに権限を含めるのを忘れたためです。

どうやって知りましたか?まあ、@ Bobbyが承認された回答の下のコメントで言うように、ログまでさらにスクロールすると、本当に例外をスローした最初の理由またはイベントが表示されます。どうやら、「最初に追加されたアクティビティがウィンドウをリークしました」というメッセージは、最初の例外が何であるかに起因する例外にすぎません。


3

以下のコードを試してください。進行状況ダイアログを閉じるといつでも機能し、インスタンスが使用可能かどうかを確認します。

try {
        if (null != progressDialog && progressDialog.isShowing()) {
            progressDialog.dismiss();
            progressDialog = null;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

2

最善の解決策は、表示する前にこれを置くprogressbarか、progressDialog

if (getApplicationContext().getWindow().getDecorView().isShown()) {

  //Show Your Progress Dialog

}

これは私にはうまくいきません。HTTP呼び出しからの応答の後にDialog.show()があり、その間に画面を回転すると、Activityが切り離されますが、Dialog.show()の前にisShown == trueがあるようで、このチェックにもかかわらずダイアログがクラッシュします
ミシャオジオブロ2018

1

コードのどこかで発生したいくつかの例外が原因で、アクティビティが予期せず終了しないことを確認してください。一般に、アクティビティがdoinBackgroundメソッドで強制終了に直面し、asynctaskがonPostexecuteメソッドに戻ると、非同期タスクで発生します。


1

これに対する別の解決策があり、それがあなたに有効であると思われるかどうかを知りたいです:主要な解決策であると思われる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の方が望ましいです。なぜなら、進行状況ダイアログをメンバーとして保持する必要がないので、fire(show)を実行するだけです。

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