java.lang.IllegalArgumentException:视图不附加到窗口pipe理器
我有一个活动,启动AsyncTask并显示进度对话框的操作持续时间。 声明的活动不是通过旋转或键盘滑动来重新创build的。
<activity android:name=".MyActivity" android:label="@string/app_name" android:configChanges="keyboardHidden|orientation" > <intent-filter> </intent-filter> </activity>
一旦任务完成,我解散对话框,但在一些手机(框架:1.5,1.6)这样的错误抛出:
java.lang.IllegalArgumentException: View not attached to window manager at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:356) at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:201) at android.view.Window$LocalWindowManager.removeView(Window.java:400) at android.app.Dialog.dismissDialog(Dialog.java:268) at android.app.Dialog.access$000(Dialog.java:69) at android.app.Dialog$1.run(Dialog.java:103) at android.app.Dialog.dismiss(Dialog.java:252) at xxx.onPostExecute(xxx$1.java:xxx)
我的代码是:
final Dialog dialog = new AlertDialog.Builder(context) .setTitle("Processing...") .setCancelable(true) .create(); final AsyncTask<MyParams, Object, MyResult> task = new AsyncTask<MyParams, Object, MyResult>() { @Override protected MyResult doInBackground(MyParams... params) { // Long operation goes here } @Override protected void onPostExecute(MyResult result) { dialog.dismiss(); onCompletion(result); } }; task.execute(...); dialog.setOnCancelListener(new OnCancelListener() { @Override public void onCancel(DialogInterface arg0) { task.cancel(false); } }); dialog.show();
从我读过的( http://bend-ing.blogspot.com/2008/11/properly-handle-progress-dialog-in.html )中看到,并且在Android源代码中看到,看起来似乎是唯一可能的情况exception是活动被破坏的时候。 但正如我所提到的,我禁止基本活动的娱乐活动。
所以任何build议都非常感激。
当我closures对话框并从onPostExecute方法完成活动时,我也会得到这个错误。 我猜有时活动会在对话成功解散之前完成。
简单而有效的解决scheme,适合我
@Override protected void onPostExecute(MyResult result) { try { if ((this.mDialog != null) && this.mDialog.isShowing()) { this.mDialog.dismiss(); } } catch (final IllegalArgumentException e) { // Handle or log or ignore } catch (final Exception e) { // Handle or log or ignore } finally { this.mDialog = null; } }
我可能有一个解决方法。
有同样的问题,我通过一个AsyncTask
将大量项目(通过文件系统)加载到一个ListView
。 如果onPreExecute()
启动ProgressDialog
,然后onPostExecute()
和onPostExecute()
onCancelled()
通过AsyncTask.cancel()
显式取消任务时调用)通过.cancel()
closures它。
当我在AsyncTask
的onCancelled()
方法中杀死对话框时(我曾在优秀的Shelves应用程序中看到这一点),得到了同样的“java.lang.IllegalArgumentException:View not attached to window manager”错误。
解决方法是在包含ProgressDialog
的AsyncTask
中创build一个公共字段:
public ProgressDialog mDialog;
然后,当我取消我的AsyncTask
时,在onDestroy()
,我也可以通过下面的方法closures对话框:
AsyncTask.mDialog.cancel();
调用AsyncTask.cancel()
在AsyncTask
触发onCancelled()
,但由于某种原因调用该方法的时候,View已经被破坏,因此取消了对话框失败。
这是解决这个问题的正确的解决scheme:
public void hideProgress() { if(mProgressDialog != null) { if(mProgressDialog.isShowing()) { //check if dialog is showing. //get the Context object that was used to great the dialog Context context = ((ContextWrapper)mProgressDialog.getContext()).getBaseContext(); //if the Context used here was an activity AND it hasn't been finished or destroyed //then dismiss it if(context instanceof Activity) { if(!((Activity)context).isFinishing() && !((Activity)context).isDestroyed()) mProgressDialog.dismiss(); } else //if the Context used wasnt an Activity, then dismiss it too mProgressDialog.dismiss(); } mProgressDialog = null; } }
这个解决scheme不是盲目捕捉所有exception,而是解决问题的根源:当用于初始化对话的活动已经完成时,试图减弱对话。 在我的Nexus 4上运行KitKat,但应该适用于所有版本的Android。
这是我的“防弹”解决scheme,这是我在这个主题上find的所有良好答案的汇编(感谢@Damjan和@Kachi)。 只有在所有其他检测方法都没有成功的情况下,这个例外才会被吞噬。 在我的情况下,我需要自动closures对话框,这是保护应用程序免受崩溃的唯一方法。 我希望它会帮助你! 如果您有评论或更好的解决scheme,请投票并留下意见。 谢谢!
public void dismissWithCheck(Dialog dialog) { if (dialog != null) { if (dialog.isShowing()) { //get the Context object that was used to great the dialog Context context = ((ContextWrapper) dialog.getContext()).getBaseContext(); // if the Context used here was an activity AND it hasn't been finished or destroyed // then dismiss it if (context instanceof Activity) { // Api >=17 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { if (!((Activity) context).isFinishing() && !((Activity) context).isDestroyed()) { dismissWithTryCatch(dialog); } } else { // Api < 17. Unfortunately cannot check for isDestroyed() if (!((Activity) context).isFinishing()) { dismissWithTryCatch(dialog); } } } else // if the Context used wasn't an Activity, then dismiss it too dismissWithTryCatch(dialog); } dialog = null; } } public void dismissWithTryCatch(Dialog dialog) { try { dialog.dismiss(); } catch (final IllegalArgumentException e) { // Do nothing. } catch (final Exception e) { // Do nothing. } finally { dialog = null; } }
我同意'Damjan'的意见。
如果使用多个对话框,应closuresonDestroy()或onStop()中的所有对话框。
那么你可能会减less频率“java.lang.IllegalArgumentException:视图不附加到窗口pipe理器”的exception发生。
@Override protected void onDestroy() { Log.d(TAG, "called onDestroy"); mDialog.dismiss(); super.onDestroy(); }
但很less超过…
为了更清楚,你可以阻止在onDestroy调用之后显示任何对话框。
我不使用如下。 但很明显。
private boolean mIsDestroyed = false; private void showDialog() { closeDialog(); if (mIsDestroyed) { Log.d(TAG, "called onDestroy() already."); return; } mDialog = new AlertDialog(this) .setTitle("title") .setMessage("This is DialogTest") .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }) .create(); mDialog.show(); } private void closeDialog() { if (mDialog != null) { mDialog.dismiss(); } } @Override protected void onDestroy() { Log.d(TAG, "called onDestroy"); mIsDestroyed = true; closeDialog(); super.onDestroy(); }
祝你好运!
用这个。
if(_dialog!=null && _dialog.isShowing()) _dialog.dismiss();
我有同样的问题,你可以通过以下方式解决:
@Override protected void onPostExecute(MyResult result) { try { if ((this.mDialog != null) && this.mDialog.isShowing()) { this.mDialog.dismiss(); } } catch (final IllegalArgumentException e) { // Handle or log or ignore } catch (final Exception e) { // Handle or log or ignore } finally { this.mDialog = null; } }
我认为你的代码是正确的,不像其他build议。 onPostExecute将在UI线程上运行。 这就是AsyncTask的全部内容 – 您不必担心调用runOnUiThread或处理处理程序。 此外,根据文档,dismiss()可以安全地从任何线程调用(不知道他们做了这个例外)。
也许这是一个计时问题,其中dialog.dismiss()被调用后,活动不再显示?
怎么样testing如果你注释掉setOnCancelListener,然后在后台任务运行的时候退出这个活动呢? 然后你的onPostExecute将尝试closures一个已经被解雇的对话框。 如果应用程序崩溃,则可以在解散之前检查对话框是否打开。
我有完全相同的问题,所以我要在代码中尝试。
亚历克斯,
我可能在这里是错误的,但我怀疑多个手机在“野外”有一个错误,导致他们在标记为静态导向的应用程序切换方向。 在我的个人电话上,我们小组使用的许多testing电话(包括droid,n1,g1,英雄)都发生了这种情况。 通常情况下,标记为静态(可能是垂直)的应用程序将使用水平方向放置一两秒钟,然后立即切换回来。 最终的结果是,即使你不想让你的应用程序切换方向,你必须做好准备。 我不知道在什么确切的条件下可以复制这种行为,我不知道它是否是特定于Android的版本。 我所知道的是,我已经看到它发生了很多次:(
我build议使用您发布的链接中提供的解决scheme,build议覆盖Activity onCreateDialog方法,并让Android OSpipe理对话框的生命周期。 在我看来,即使你不希望你的活动改变方向,它是在某个地方切换方向。 您可以尝试追踪一种始终阻止方向切换的方法,但是我试图告诉您,我个人不相信在市场上所有当前的Android手机上都有一种可靠的方法。
大部分时间对我来说最有效的是validation活动是否没有完成。
if (!mActivity.isFinishing()) { dialog.dismiss(); }
首先做error handling,当你试图closures对话框。
if ((progressDialog != null) && progressDialog.isShowing()) { progressDialog.dismiss(); progressDialog = null; }
如果这不解决,然后解雇它的onStop()方法的活动。
@Override protected void onStop() { super.onStop(); if ((progressDialog != null) && progressDialog.isShowing()) { progressDialog.dismiss(); progressDialog = null; } }
使用button同步服务器列表时,我遇到了同样的问题:1)我单击button2)从服务器下载列表时显示进度对话框3)将设备转到另一个方向4)java.lang .IllegalArgumentException:在progress.dismiss()过程中,View未附加到AsyncTask的postExecute()上的窗口pipe理器。
当我尝试修复我想,即使问题不发生我的列表不显示所有项目。
我想,我所希望的是AsyncTask在活动beign被销毁之前完成(并消除对话),所以我使asynctask对象成为一个属性并覆盖了onDestroy()方法。
如果asynctask花了很多时间,用户可能会觉得设备很慢,但我认为这是他在尝试改变设备方向时所付出的代价,而进度对话框正在显示。 即使这需要一段时间的应用程序不会崩溃。
private AsyncTask<Boolean, Void, Boolean> atask; @Override protected void onDestroy() { if (atask!=null) try { atask.get(); } catch (InterruptedException e) { } catch (ExecutionException e) { } super.onDestroy(); }
@Override protected void onPostExecute(Void result) { super.onPostExecute(result); if (progressDialog != null && progressDialog.isShowing()) { Log.i(TAG, "onPostexucte"); progressDialog.dismiss(); } }
声明的活动不是通过旋转或键盘滑动来重新创build的。
刚刚得到同样的问题。 修复API级别13或更高。
从Android文档:
注意:如果您的应用程序的目标API级别为13或更高(由minSdkVersion和targetSdkVersion属性声明),则还应该声明“screenSize”configuration,因为当设备在纵向和横向之间切换时,configuration也会更改。
所以我改变了我的清单:
<activity android:name="MyActivity" android:configChanges="orientation|screenSize" android:label="MyActivityName" > </activity>
现在它工作正常。 当我旋转手机时,活动不会重新创build,进度对话框和视图保持不变。 对我来说没有错误。
Migh下面的代码适合你,它对我来说工作得很好:
private void viewDialog() { try { Intent vpnIntent = new Intent(context, UtilityVpnService.class); context.startService(vpnIntent); final View Dialogview = View.inflate(getBaseContext(), R.layout.alert_open_internet, null); final WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_DIM_BEHIND, PixelFormat.TRANSLUCENT); params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL; windowManager.addView(Dialogview, params); Button btn_cancel = (Button) Dialogview.findViewById(R.id.btn_canceldialog_internetblocked); Button btn_okay = (Button) Dialogview.findViewById(R.id.btn_openmainactivity); RelativeLayout relativeLayout = (RelativeLayout) Dialogview.findViewById(R.id.rellayout_dialog); btn_cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { try { if (Dialogview != null) { // ( (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview); windowManager.removeView(Dialogview); } } catch (final IllegalArgumentException e) { e.printStackTrace(); // Handle or log or ignore } catch (final Exception e) { e.printStackTrace(); // Handle or log or ignore } finally { try { if (windowManager != null && Dialogview != null) { // ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview); windowManager.removeView(Dialogview); } } catch (Exception e) { e.printStackTrace(); } } // ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview); // windowManager.removeView(Dialogview); } }); } }); btn_okay.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Handler handler = new Handler(Looper.getMainLooper()); handler.post(new Runnable() { @Override public void run() { // ((WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE)).removeView(Dialogview); try { if (windowManager != null && Dialogview != null) windowManager.removeView(Dialogview); Intent intent = new Intent(getBaseContext(), SplashActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); context.startActivity(intent); } catch (Exception e) { windowManager.removeView(Dialogview); e.printStackTrace(); } } }); } }); } catch (Exception e) { //` windowManager.removeView(Dialogview); e.printStackTrace(); } }
如果你从后台服务中调用它,不要全局定义你的视图。
- Android:如何以编程方式打开和closures屏幕?
- 如何以编程方式“重新启动”Android应用程序?
- SimpleDateFormat(string模板,语言环境语言环境),例如用于ASCIIdate的Locale.US
- getExternalFilesDir和getExternalStorageDirectory()之间的差异
- 如何检测Android中的布局方向变化?
- 如何在Android App中实现Rate Itfunction
- Android Studio 3.0错误。 迁移本地模块的依赖configuration
- 在Android中使用VideoView播放video
- 如何以编程方式locking/解锁屏幕?