Android ProgressDialog:如何防止窗口泄漏
我使用ProgressDialog阻止用户在设备从internet下载内容时进行交互 在我的客户设法产生此错误之前,一切都正常:Android ProgressDialog:如何防止窗口泄漏,android,memory-leaks,progressdialog,Android,Memory Leaks,Progressdialog,我使用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
"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)"
如果我把它改成这样,它能解决问题吗
this.runOnUiThread(new Runnable() {
public void run() {
progressDialog = ProgressDialog.show(PixelRainActivity.staticThis, "",PixelRainActivity.staticThis.getResources().getString( R.string.draftProgressMessage), true);
}
});
不要使用
ProgressDialog.show()
,而是尝试使用
Activity.showDialog()
它将自动为您管理对话框
,并防止泄漏
编辑:当你调用
showDialog(int)
时,它将触发活动。onCreateDialog(int)
在那里你可以创建你想要的对话框并返回你想要显示的对话框。我在进度对话框和后台任务中遇到了类似的问题。AsyncTask()使我可以更干净地完成这两项工作,而不必使用泄漏的窗口。泄漏可能来自您的像素活动。staticThis
属性。如果保留对某个活动的引用,即使在该活动被销毁之后,也会发生内存泄漏
最简单的修复方法是使用应用程序的上下文。将方法onCreate()
中的staticThis=this
行更改为staticThis=this.getApplicationContext()
,它应该可以工作(如果不是这样的话,将staticThis
的类型更改为Context
)天鹅座有一个使用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);
}
使用:
在结束工作时如果您正在使用任何线程
或异步任务
并从internet下载内容并显示进度条
,如果在异步任务
中显示进度,则在活动
停止时也应使用对话框片段
或取消进度对话框
,并覆盖oncancel
回调方法和取消
进度对话框
活动
或片段
中的窗口泄漏
实际上是由于您试图添加一个窗口而发生的,当它显示在前台时
,但当您按下home键时,它会暂停,然后通过顶部的停止。因此,您的CustomView
仍然连接到现在已消失的窗口。因此,根据系统,您的CustomView
占用了它未释放的空间。最好使用AsyncTask
在后台从internet获取内容。但是,不需要传递静态上下文。和活动
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;
}
}
私有类YourAsynTask扩展了异步任务
{
私人语境;
私有进程对话;
//在构造函数中传递上下文
公共YourAsynTask(上下文)
{
this.context=上下文;
}
//显示onPre的进展
@凌驾
受保护的void onPreExecute()
{
//在这里显示进度代码。
progressDialog=progressDialog.show(上下文“,”正在加载。请稍候…,true);
}
//关闭onPost中的“进度”对话框
@凌驾
受保护的void OnPostExecute(字符串响应)
{
如果(progressDialog!=null)
progressDialog.disclose();
progressDialog=null;
}
}
在某些情况下,如果进度对话框仍然可见,则必须在onDetach
或onDestroy
中进行验证。
像这样:
在活动终止之前,尝试调用progressDialog.dismise()
。我的问题是这样解决的。当另一个活动进入前台时,只需调用cancel()方法
@Override
protected void onStop() {
super.onStop();
this.mProgress.cancel();
}
我遇到了这个例外
@Override
protected void onResume() {
super.onResume();//at this line
showProgressDialog();
}
此修复对我有效:
@Override
protected void onResume() {
showProgressDialog();
super.onResume();
}
我也遇到了同样的问题,只有在活动暂停时打开对话框时才会出现。是这样吗?或者可能是在更改方向时?请更新已接受的答案,使其使用discover
但不使用Activity.showDialog()我需要将a ID传递给对话框,然后如何显示进度对话框?对我来说不起作用。我正在异步任务的onPreExecute()中使用progressDialog.show()。我得到:android.view.WindowManager$BadTokenException:无法添加窗口--标记null不适用于应用程序为了创建对话框,您必须传递的不是上下文,而是活动。因此,此.getApplicationContext()不正确根据此,在这种情况下使用getApplicationContext将抛出一个错误:-1@Guillaume Brunerie-您必须将活动实例作为上下文传递,因为该操作是在UI中执行的。因此传递getApplicationContext()将导致异常。该链接是一个死端。我错误地调用了hide而不是disclose()。谢谢。要添加答案:您可能应该在onDestroy()
中调用progressDialog.dismise()
(但在调用super.onDestroy()
)之前,最好通过活动检查活动是否处于活动状态!=空&!activity.isFinishing()
在显示进度对话框之前
@Override
protected void onStop() {
super.onStop();
this.mProgress.cancel();
}
@Override
protected void onResume() {
super.onResume();//at this line
showProgressDialog();
}
@Override
protected void onResume() {
showProgressDialog();
super.onResume();
}