我正在使用ProgressDialog来防止用户在设备从Internet下载内容时进行交互。
一切正常,直到我的客户设法产生此错误:
"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);
}
});
泄漏可能来自您的PixelRainActivity.staticThis
属性。如果要保留对活动的引用,即使该活动已被销毁,也存在内存泄漏。
最简单的解决方法是改用应用程序的Context
。将方法staticThis = this
中的onCreate()
行更改为staticThis = this.getApplicationContext()
,它应该起作用(如果不是这样,则将staticThis
的类型更改为Context
)
在活动被杀死之前,请尝试致电progressDialog.dismiss()
。我像这样固定了我。
用途:
progressDialog.dismiss();
最终工作中
在某些情况下,如果仍然显示进度对话框,则必须在onDetach
或onDestroy
中进行验证。像这样:
@Override
public void onDetach() {
if (mProgressDialog != null && mProgressDialog.isShowing())
mProgressDialog.dismiss();
super.onDetach();
}
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);
}
代替使用ProgressDialog.show()
,请尝试使用
[Activity.showDialog()
,它将自动为您管理Dialog
,并防止泄漏。
编辑:当您调用showDialog(int)
时,它将触发Activity.onCreateDialog(int)
,您可以在其中创建所需的Dialog
,并返回要显示的Dialog
。
我在进度对话框和后台任务中遇到了类似的问题。 AsyncTask(http://android-developers.blogspot.de/2009/05/painless-threading.html)使我可以做得更干净,并且没有泄漏的窗口。
最好使用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;
}
}
[如果您正在使用thread
或AsyncTask
,并从互联网下载内容并显示progress bar
,则当DialogFragment
停止时也应使用dialog
或取消进度Activity
,如果您正在Asynctask
首先取消Asynctask
并覆盖oncancel
回调方法和dismiss
在那里进行对话。
Window leak
或Activity
中的[fragment
实际上是由于您试图添加一个窗口而显示的,而它却显示在foreground
上,但是实际上,当您按下房屋时它会暂停然后通过onStop
()停止。因此,您的CustomView
仍然附着在现在消失的窗口上。因此,根据系统,您的customView
占据了未被释放的空间。
只需在另一个活动进入前台时调用cancel()方法。
@Override
protected void onStop() {
super.onStop();
this.mProgress.cancel();
}