ProgressDialog:如何防止泄漏窗口

时间:2011-07-07 17:34:03

标签: android memory-leaks progressdialog

我正在使用ProgressDialog阻止用户在设备从互联网上下载时进行交互。

一切正常,直到我的客户设法产生这个错误:

"07-06 17:10:50.363: ERROR/WindowManager(8821): Activity android.pixelrain.framework.PixelRainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@463f3e50 that was originally added here
07-06 17:10:50.363: ERROR/WindowManager(8821): android.view.WindowLeaked: Activity android.pixelrain.framework.PixelRainActivity has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@463f3e50 that was originally added here
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewRoot.<init>(ViewRoot.java:251)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:148)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.Window$LocalWindowManager.addView(Window.java:424)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.Dialog.show(Dialog.java:241)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.ProgressDialog.show(ProgressDialog.java:107)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.ProgressDialog.show(ProgressDialog.java:90)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.HTTPHelper.DraftHelper.getDraft(DraftHelper.java:70)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.online.OnlineRetriver.getDraft(OnlineRetriver.java:312)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.HTTPHelper.DraftButtonGL.loadDraft(DraftButtonGL.java:72)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.HTTPHelper.DraftButtonGL.isTouched(DraftButtonGL.java:89)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.opengl.views.game.QuickStartGL.touchEnded(QuickStartGL.java:160)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.game.GameHandler.onTouchEvent(GameHandler.java:277)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.pixelrain.opengl.GLSurfaceViewChipmunk.onTouchEvent(GLSurfaceViewChipmunk.java:27)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.View.dispatchTouchEvent(View.java:3765)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:944)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1701)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1116)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.Activity.dispatchTouchEvent(Activity.java:2093)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1685)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.view.ViewRoot.handleMessage(ViewRoot.java:1802)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.os.Looper.loop(Looper.java:144)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at android.app.ActivityThread.main(ActivityThread.java:4937)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at java.lang.reflect.Method.invokeNative(Native Method)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at java.lang.reflect.Method.invoke(Method.java:521)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
07-06 17:10:50.363: ERROR/WindowManager(8821):     at dalvik.system.NativeStart.main(Native Method)"

我不知道如何解决这个问题。

任何想法是什么导致了这个以及如何解决它?

日志将错误追溯到此行:

    progressDialog = ProgressDialog.show(PixelRainActivity.staticThis, "",PixelRainActivity.staticThis.getResources().getString( R.string.draftProgressMessage), true);
如果我将其更改为:

,它会解决问题吗?
this.runOnUiThread(new Runnable() {
            public void run() {
                progressDialog = ProgressDialog.show(PixelRainActivity.staticThis, "",PixelRainActivity.staticThis.getResources().getString( R.string.draftProgressMessage), true);
            }
        });

11 个答案:

答案 0 :(得分:113)

使用:

progressDialog.dismiss();

在最后的工作中

答案 1 :(得分:17)

泄漏可能来自您的PixelRainActivity.staticThis属性。如果您保留对某个活动的引用,即使此活动已被销毁,您也会发生内存泄漏。

最简单的解决方法是使用应用程序的Context代替。将方法staticThis = this中的onCreate()行更改为staticThis = this.getApplicationContext(),它应该有效(如果情况不是这样,则将staticThis的类型更改为Context

答案 2 :(得分:4)

在某些情况下,如果进度对话框仍然可见,则必须在System.out.println()onDetach中进行验证。 像这样:

onDestroy

答案 3 :(得分:2)

cygnus最好使用showDialog(MY_INT),其中MY_INT只是你选择的一些常量值,只是为了区别于你以这种方式启动的任何其他类似对话框。你用dismissDialog(MY_INT)以相同的方式取下它。只是不要从你的onPause方法启动它。您可能希望从用户将要访问的活动的onResume方法中执行此操作。然后你覆盖该活动的onCreateDialog方法,如下所示:

@Override
protected Dialog onCreateDialog(int id) {
    if(id == MY_INT) {
        ProgressDialog progressDialog = new ProgressDialog(this);
        progressDialog.setMessage("Your message string");
        return progressDialog;
    }
    return super.onCreateDialog(id);
}

答案 4 :(得分:1)

请尝试使用

,而不是使用ProgressDialog.show()

Activity.showDialog()应自动为您管理Dialog并防止泄密。

编辑:当您致电showDialog(int)时,它会触发Activity.onCreateDialog(int),您可以在其中创建所需的Dialog并返回您要显示的Dialog

答案 5 :(得分:0)

我遇到了类似的问题,包括进度对话框和后台任务。 AsyncTask(http://android-developers.blogspot.de/2009/05/painless-threading.html)允许我更干净地完成这两项工作而没有泄露的窗口。

答案 6 :(得分:0)

如果您使用任何threadAsyncTask并从互联网下载内容并显示progress bar,则应DialogFragment使用dialog或取消进度Activity { {1}}如果您在Asynctask拳头取消Asynctask中显示进度并覆盖oncancel回调方法和dismiss进度对话,也会停止。

Window leakActivity中的{p> fragment实际上是因为您尝试添加一个窗口而显示它在foreground上,但是当您正在按住它暂停,然后通过onStop()停止。所以你的CustomView仍然附着在现在已经消失的窗口上。因此根据系统你的customView占据了它没有释放的空间。

答案 7 :(得分:0)

最好使用AsyncTask在后​​台从互联网上获取内容。并且不需要传递静态上下文。和活动

new YourAsyncTask(context).execute();

像上面一样调用AsyncTask

private class YourAsynTask extends AsyncTask<String,Void,String>
{
 private Context context;
 private ProgressDialog progressDialog;

 //pass context in constructor
  public YourAsynTask(Context context)
  {
     this.context = context;
  }

  //show progress in onPre 
  @Override
  protected void onPreExecute()
  {
    //show Progress code here.
    progressDialog = ProgressDialog.show(context, "", "Loading. Please wait...", true);
  }

  //dismiss Progress dialog in onPost
  @Override 
  protected void OnPostExecute(String response)
  {
    if(progressDialog!=null)
     progressDialog.dismiss();
     progressDialog = null;
  }
}

答案 8 :(得分:0)

当另一个活动进入前台时,只需调用cancel()方法即可。

@Override
protected void onStop() {
   super.onStop();
   this.mProgress.cancel();
}

答案 9 :(得分:0)

我是这个例外

@Override
    protected void onResume() {
        super.onResume();//at this line
        showProgressDialog();
    }

此修复程序对我有用:

  @Override
        protected void onResume() {
            showProgressDialog();
            super.onResume();
        }

答案 10 :(得分:-2)

在活动被杀之前尝试调用progressDialog.dismiss()。我这样修好了。