Android活动泄漏了窗口:com.android.internal.policy.impl.phonewindow$decorview问题。

72

我正在处理一个Android应用程序,以显示网络错误。

NetErrorPage.java

package exp.app;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class NetErrorPage extends Activity implements OnClickListener {    

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.neterrorlayout);
        Button reload=(Button)findViewById(R.id.btnReload);
        reload.setOnClickListener(this);    
        showInfoMessageDialog("Please check your network connection","Network Alert"); 
    }

    public void onClick(View arg0)             
        {
            if(isNetworkAvailable())
            {                   
                Intent myIntent = new Intent((Activity)NetErrorPage.this, MainActivity.class);   
                myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);              
                ((Activity)NetErrorPage.this).startActivity(myIntent);
                finish();
            }
            else
                showInfoMessageDialog("Please check your network connection","Network Alert");
    }

    public void showInfoMessageDialog(String message,String title)
       {
        AlertDialog alertDialog = new AlertDialog.Builder(NetErrorPage.this).create();
        alertDialog.setTitle("Network Alert");
        alertDialog.setMessage(message);
        alertDialog.setButton("OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,int which) 
                    {   
                        dialog.cancel();
                    }
                });            
        alertDialog.show();
    }

 private boolean isNetworkAvailable()
    {
        NetworkInfo ActiveNetwork;
        @SuppressWarnings("unused")
        String IsNetworkConnected;
        @SuppressWarnings("unused")
        String ConnectionType;
        ConnectivityManager connectivitymanager;
        connectivitymanager=(ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);        
        try
        {           
            ActiveNetwork=connectivitymanager.getActiveNetworkInfo();
            ConnectionType=ActiveNetwork.getTypeName(); 
            IsNetworkConnected=String.valueOf(ActiveNetwork.getState());
            return true;                        
        }
        catch(Exception error)
        {
                return false;
        }
    }    
}

但我收到以下错误:

08-17 11:59:08.019: E/WindowManager(16460): Activity exp.app.NetErrorPage has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@40534a18 that was originally added here
08-17 11:59:08.019: E/WindowManager(16460): android.view.WindowLeaked: Activity exp.app.NetErrorPage has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@40534a18 that was originally added here
08-17 11:59:08.019: E/WindowManager(16460):     at android.view.ViewRoot.<init>(ViewRoot.java:263)
08-17 11:59:08.019: E/WindowManager(16460):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
08-17 11:59:08.019: E/WindowManager(16460):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
08-17 11:59:08.019: E/WindowManager(16460):     at android.view.Window$LocalWindowManager.addView(Window.java:424)
08-17 11:59:08.019: E/WindowManager(16460):     at android.app.Dialog.show(Dialog.java:241)
08-17 11:59:08.019: E/WindowManager(16460):     at sync.directtrac.NetError.showInfoMessageDialog(NetErrorPage.java:114)
08-17 11:59:08.019: E/WindowManager(16460):     at sync.directtrac.NetError.onCreate(NetErrorPage.java:26)
08-17 11:59:08.019: E/WindowManager(16460):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-17 11:59:08.019: E/WindowManager(16460):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1615)
08-17 11:59:08.019: E/WindowManager(16460):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1667)
08-17 11:59:08.019: E/WindowManager(16460):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-17 11:59:08.019: E/WindowManager(16460):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935)
08-17 11:59:08.019: E/WindowManager(16460):     at android.os.Handler.dispatchMessage(Handler.java:99)
08-17 11:59:08.019: E/WindowManager(16460):     at android.os.Looper.loop(Looper.java:130)
08-17 11:59:08.019: E/WindowManager(16460):     at android.app.ActivityThread.main(ActivityThread.java:3687)
08-17 11:59:08.019: E/WindowManager(16460):     at java.lang.reflect.Method.invokeNative(Native Method)
08-17 11:59:08.019: E/WindowManager(16460):     at java.lang.reflect.Method.invoke(Method.java:507)
08-17 11:59:08.019: E/WindowManager(16460):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:867)
08-17 11:59:08.019: E/WindowManager(16460):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:625)
08-17 11:59:08.019: E/WindowManager(16460):     at dalvik.system.NativeStart.main(Native Method)

我已经搜索了更多内容,但是我没有任何正确的想法来解决这个问题。

我想要的是,在加载此页面时,应该添加布局并显示对话框。

请帮助我解决这个错误。

注意:我也尝试过这个方法。

@Override
    protected void onResume() {
    super.onResume();
        runOnUiThread(new Runnable() {
            public void run() {
                showInfoMessageDialog("Please check your network connection","Network Alert");
            }
        });

    }

showInfoMessageDialog 方法包含什么内容? - Praveenkumar
我已经编辑了我的代码... 请检查。 - Ponmalar
1
@Eric:这是在点击按钮时显示对话框,但我正在询问如何在oncreate中显示。 - Ponmalar
@Yahor10:我不明白你在问什么。 - Ponmalar
@ChiragRaval:第114行是“alertDialog.show();”。 - Ponmalar
显示剩余14条评论
8个回答

77
感谢大家给我提出了许多建议,最终我找到了一个解决方案。我启动了NetErrorPage intent两次。第一次,在页面开始事件中检查网络连接是否可用,并启动intent。第二次,在OnReceivedError事件中如果页面出现错误,则启动intent。因此,在第一个对话框关闭之前,第二个对话框就被调用了,这就导致了错误。

错误原因:在关闭第一个对话框之前,我调用了showInfoMessageDialog方法两次。

现在我已经移除了第二次调用,问题已经解决 :-)


我的理解是在关闭第一个对话框之前我们不能调用第二个对话框?如果我错了,请纠正我。 - Lavekush Agrawal
@Lavekush:我们可以同时打开许多对话框,但如果对话框在新的活动中,并且您正在调用意图来调用该对话框,将会导致错误。如果您从活动中调用并且对话框在同一活动中,则不会导致错误,我希望如此。 - Ponmalar

60

dialog.cancel();改为dialog.dismiss();

解决方案是在退出Activity之前,在NetErrorPage.java:114中调用您创建的Dialog上的dismiss(),例如在onPause()中。

视图有一个对其父Context的引用(取自构造函数参数)。如果您离开一个Activity而不销毁Dialog和其他动态创建的View,它们仍然保留对您的Activity的此引用(如果您使用它作为Context创建:如new ProgressDialog(this)),因此无法被GC收集,导致内存泄漏。


2
@Ponmalar,我检查了你的代码,我认为出现了错误。请在这个活动中重写onPause方法并在其中关闭你的警告对话框。你应该在类级别上创建AlertDialog alertDialog变量(即在onCreate方法之前声明它),并在onPause方法中关闭它。这将解决你的问题。 - Chirag
为什么会发生这种情况的简短描述。 - android developer
谢谢。在我的情况下,必须写成 dialog.dismiss() 而不是 dialog.hide()。 - CoolMind
如果您查看cancel()函数的代码,它已经在内部调用了dismiss(),但是它还将调用您注册的DialogInterface.OnCancelListener。因此,在理论上,对其中一个进行优先选择并不会有任何区别。 - Wahib Ul Haq
@Override protected void onPause() { super.onPause(); //APP WILL CRASH IF THIS IS NOT PRESENT loadingDialog.dismiss(); } - Reejesh
显示剩余3条评论

5
在我的情况下,finish()方法是在一个对话框显示后立即执行的。

即使是 pause() 在我的情况下也会出现这种情况。 - FindOutIslamNow
@FindOutIslamNow,你指的是哪个方法?onPause()吗? - CoolMind
是的,它也会导致显示的窗口/对话框泄漏。 - FindOutIslamNow
@FindOutIslamNow,谢谢。如果您知道一个导致onPause()的命令,您可以将其写成一个新答案或在此处写下。 - CoolMind

5
请尝试这种方法并让我知道:
Context mContext;
@Override
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.neterrorlayout);

   mContext=NetErrorPage.this;
   Button reload=(Button)findViewById(R.id.btnReload);
   reload.setOnClickListener(this);    
   showInfoMessageDialog("Please check your network connection","Network Alert"); 
}
public void showInfoMessageDialog(String message,String title)
{
   new AlertDialog.Builder(mContext)
   .setTitle("Network Alert");
   .setMessage(message);
   .setButton("OK",new DialogInterface.OnClickListener() {
       public void onClick(DialogInterface dialog,int which) 
       {   
          dialog.cancel();
       }
   })
   .show();
}

这完全是上下文问题,没有其他的。 - Haresh Chaudhary
非常抱歉,Haresh,请检查我的编辑代码。我的活动名称是“NetErrorPage”。 - Ponmalar
请粘贴完整的活动代码。 - Haresh Chaudhary
请检查我的修改后的代码,告诉我需要做哪些更改。 - Ponmalar
我得到了一个解决方案......你的建议可能会给其他人提供解决方案,所以我会点赞。 - Ponmalar

3
对话框需要在Activity的窗口状态初始化后才能启动,这只会在onResume之后发生。因此,请调用:
runOnUIthread(new Runnable(){

    showInfoMessageDialog("Please check your network connection","Network Alert");
});

在您的OnResume功能中。请不要在OnCreate中创建对话框
编辑:

使用这个

Handler h = new Handler();

h.postDelayed(new Runnable(){

        showInfoMessageDialog("Please check your network connection","Network Alert");
    },500);

在您的OnResume中,使用showOnUiThread而不是直接显示。

请检查我编辑过的代码,告诉我需要做哪些修改。 - Ponmalar
在onResume中使用此代码,而不是在onCreate中使用showInfoMessageDialog。 - nandeesh
super调用应该始终位于onResume方法的顶部。 - nandeesh
我得到了一个解决方案......你的建议可能会给其他人提供解决方案,所以我会点赞。 - Ponmalar

1
 @Override
    protected void onPostExecute(final Boolean success) {
        mProgressDialog.dismiss();
        mProgressDialog = null;

将值设置为 null 对我有用


0
我解决这个问题的方法是在对话框中不调用意图。 **** 根据活动或片段使用适用的语法
@Override
public void onClick(DialogInterface dialog, int which) {
    checkvariable= true;
    getActivity().finish();
}

@Override
public void onStop() {
    super.onStop();
    if (checkvariable) {
        startActivity(intent); 
    }
}

0

我遇到了这个错误但很有趣地解决了。首先,我在API 17级别遇到了这个错误。当我调用一个没有进度对话框的线程(AsyncTask或其他)然后再使用进度对话框调用另一个线程方法时,我遇到了崩溃,原因是关于进度对话框的使用。

在我的情况下,有两个结果:

  • 我在第一个线程开始之前取得了进度对话框的show(); 方法,然后在最后一个线程结束之前取得了进度对话框的dismiss(); 方法。

所以:

ProgresDialog progressDialog = new ...

//configure progressDialog 

progressDialog.show();

start firstThread {
...
}

...

start lastThread {
...
} 

//be sure to finish threads

progressDialog.dismiss();
  • 这很奇怪,但是这个错误至少对我来说有一种自我销毁的能力 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接