视图不附加到窗口pipe理器崩溃

我正在使用ACRA报告应用程序崩溃。 我得到一个View not attached to window manager错误消息,并认为我已经通过包装pDialog.dismiss(); 在if语句中:

 if (pDialog!=null) { if (pDialog.isShowing()) { pDialog.dismiss(); } } 

它已经减less了View not attached to window manager崩溃我收到,但我仍然得到一些,我不知道如何解决它。

错误信息:

 java.lang.IllegalArgumentException: View not attached to window manager at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:425) at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:327) at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:83) at android.app.Dialog.dismissDialog(Dialog.java:330) at android.app.Dialog.dismiss(Dialog.java:312) at com.package.class$LoadAllProducts.onPostExecute(class.java:624) at com.package.class$LoadAllProducts.onPostExecute(class.java:1) at android.os.AsyncTask.finish(AsyncTask.java:631) at android.os.AsyncTask.access$600(AsyncTask.java:177) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:644) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:176) at android.app.ActivityThread.main(ActivityThread.java:5419) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:525) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862) at dalvik.system.NativeStart.main(Native Method) 

代码片段:

 class LoadAllProducts extends AsyncTask<String, String, String> { /** * Before starting background thread Show Progress Dialog * */ @Override protected void onPreExecute() { super.onPreExecute(); pDialog = new ProgressDialog(CLASS.this); pDialog.setMessage("Loading. Please wait..."); pDialog.setIndeterminate(false); pDialog.setCancelable(false); pDialog.show(); } /** * getting All products from url * */ protected String doInBackground(String... args) { // Building Parameters doMoreStuff("internet"); return null; } /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String file_url) { // dismiss the dialog after getting all products if (pDialog!=null) { if (pDialog.isShowing()) { pDialog.dismiss(); //This is line 624! } } something(note); } } 

performance:

  <activity android:name="pagename.CLASS" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|screenLayout" android:label="@string/name" > </activity> 

我错过了什么来阻止这次事故的发生?

如何重现该错误:

  1. 在您的设备上启用此选项: Settings -> Developer Options -> Don't keep Activities
  2. AsyncTask正在执行并显示ProgressDialog时,请按Homebutton。

Android操作系统一旦隐藏就会摧毁一个活动。 当onPostExecute被调用时, Activity将处于“完成”状态, ProgressDialog将不会附加到Activity

如何解决它:

  1. 检查onPostExecute方法中的活动状态。
  2. closuresonDestroy方法中的ProgressDialog 。 否则,会抛出android.view.WindowLeakedexception。 这个exception通常来自当活动结束时仍然有效的对话框。

试试这个固定的代码:

 public class YourActivity extends Activity { <...> private void showProgressDialog() { if (pDialog == null) { pDialog = new ProgressDialog(StartActivity.this); pDialog.setMessage("Loading. Please wait..."); pDialog.setIndeterminate(false); pDialog.setCancelable(false); } pDialog.show(); } private void dismissProgressDialog() { if (pDialog != null && pDialog.isShowing()) { pDialog.dismiss(); } } @Override protected void onDestroy() { dismissProgressDialog(); super.onDestroy(); } class LoadAllProducts extends AsyncTask<String, String, String> { /** * Before starting background thread Show Progress Dialog * */ @Override protected void onPreExecute() { showProgressDialog(); } /** * getting All products from url * */ protected String doInBackground(String... args) { doMoreStuff("internet"); return null; } /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String file_url) { if (YourActivity.this.isDestroyed()) { // or call isFinishing() if min sdk version < 17 return; } dismissProgressDialog(); something(note); } } } 

问题可能是Activityfinishedprogress of finishing

添加一个检查isFinishing ,并且只有当这个false是closures对话框

 if (!YourActivity.this.isFinishing() && pDialog != null) { pDialog.dismiss(); } 

isFinishing: 检查这个活动是否在完成过程中,要么是因为你finish了或者有人要求完成。

看看这个守则是如何在这里工作的:

调用asynchronous任务后,asynchronous任务在后台运行。 这是可取的。 现在,这个Async任务有一个附加到Activity的进度对话框,如果你问的是什么,请看代码:

 pDialog = new ProgressDialog(CLASS.this); 

您将Class.this作为上下文传递给参数。 所以进度对话框仍然附加到活动。

现在考虑一下情况:如果我们尝试使用finish()方法完成活动,而asynchronous任务正在进行,则您尝试访问附加到活动的资源的点即活动不是在那里。

因此你得到:

 java.lang.IllegalArgumentException: View not attached to window manager 

解决scheme:

1)确保对话框在活动结束之前被解除或取消。

2)完成活动,只有在对话框被解除后,即asynchronous任务结束。

基于@erakitin的答案,但也兼容Android版本<API级别17.可悲的是Activity.isDestroyed()只支持API级别17,所以如果你像我一样瞄准一个较旧的API级别,你将不得不自己检查一下。 那之后没有看到View not attached to window managerexception。

示例代码

 public class MainActivity extends Activity { private TestAsyncTask mAsyncTask; private ProgressDialog mProgressDialog; private boolean mIsDestroyed; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (condition) { mAsyncTask = new TestAsyncTask(); mAsyncTask.execute(); } } @Override protected void onResume() { super.onResume(); if (mAsyncTask != null && mAsyncTask.getStatus() != AsyncTask.Status.FINISHED) { Toast.makeText(this, "Still loading", Toast.LENGTH_LONG).show(); return; } } @Override protected void onDestroy() { super.onDestroy(); mIsDestroyed = true; if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.dismiss(); } } public class TestAsyncTask extends AsyncTask<Void, Void, AsyncResult> { @Override protected void onPreExecute() { super.onPreExecute(); mProgressDialog = ProgressDialog.show(MainActivity.this, "Please wait", "doing stuff.."); } @Override protected AsyncResult doInBackground(Void... arg0) { // Do long running background stuff return null; } @Override protected void onPostExecute(AsyncResult result) { // Use MainActivity.this.isDestroyed() when targeting API level 17 or higher if (mIsDestroyed)// Activity not there anymore return; mProgressDialog.dismiss(); // Handle rest onPostExecute } } } 
 @Override public void onPause() { super.onPause(); if(pDialog != null) pDialog .dismiss(); pDialog = null; } 

参考这个 。

覆盖onConfigurationChanged并closures进度对话框。 如果在纵向上创build进度对话框并在横向上解散,则会抛出视图不附加到窗口pipe理器错误。

还要停止进度条并停止onPause(),onBackPressed和onDestroy方法中的asynchronous任务。

 if(asyncTaskObj !=null && asyncTaskObj.getStatus().equals(AsyncTask.Status.RUNNING)){ asyncTaskObj.cancel(true); } 

覆盖活动的onDestroy并closures对话框并使其为空

 protected void onDestroy () { if(mProgressDialog != null) if(mProgressDialog.isShowing()) mProgressDialog.dismiss(); mProgressDialog= null; } 

对于在Fragment创build的Dialog ,我使用以下代码:

 ProgressDialog myDialog = new ProgressDialog(getActivity()); myDialog.setOwnerActivity(getActivity()); ... Activity activity = myDialog.getOwnerActivity(); if( activity!=null && !activity.isFinishing()) { myDialog.dismiss(); } 

我使用这种模式来处理Fragment可能从Activity分离出来的情况。

这个问题是因为您的活动在调用dismiss函数之前就已经完成了。 处理例外情况,并检查您的ADB日志确切的原因。

 /** * After completing background task Dismiss the progress dialog * **/ protected void onPostExecute(String file_url) { try { if (pDialog!=null) { pDialog.dismiss(); //This is line 624! } } catch (Exception e) { // do nothing } something(note); } 

我有办法重现这个exception。

我使用2个AsyncTask 。 一个任务长,另一个任务短。 完成短任务后,调用finish() 。 当长任务完成并调用Dialog.dismiss() ,它崩溃。

这是我的示例代码:

 public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private ProgressDialog mProgressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG, "onCreate"); new AsyncTask<Void, Void, Void>(){ @Override protected void onPreExecute() { mProgressDialog = ProgressDialog.show(MainActivity.this, "", "plz wait...", true); } @Override protected Void doInBackground(Void... nothing) { try { Log.d(TAG, "long thread doInBackground"); Thread.sleep(20000); } catch (InterruptedException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void result) { Log.d(TAG, "long thread onPostExecute"); if (mProgressDialog != null && mProgressDialog.isShowing()) { mProgressDialog.dismiss(); mProgressDialog = null; } Log.d(TAG, "long thread onPostExecute call dismiss"); } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); new AsyncTask<Void, Void, Void>(){ @Override protected Void doInBackground(Void... params) { try { Log.d(TAG, "short thread doInBackground"); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } return null; } @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); Log.d(TAG, "short thread onPostExecute"); finish(); Log.d(TAG, "short thread onPostExecute call finish"); } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy"); } } 

你可以试试这个,找出解决这个问题的最好方法。 从我的学习来看,至less有4种方法可以解决这个问题:

  1. @ erakitin的回答:调用isFinishing()来检查活动的状态
  2. @Kapé的回答:设置标志来检查活动的状态
  3. 使用try / catch来处理它。
  4. onDestroy()调用AsyncTask.cancel(false) onDestroy() 。 它会阻止asynctask执行onPostExecute()而是执行onPostExecute()
    注意: onPostExecute()仍然会执行,即使你在较旧的Android操作系统上调用AsyncTask.cancel(false) ,如Android 2.XX

你可以为你select最好的一个。

最佳解决scheme 检查第一个上下文是活动上下文还是应用上下文,如果活动上下文只检查活动是否完成,则调用dialog.show()dialog.dismiss();

看到下面的示例代码 …希望它会有帮助!

显示对话框

 if (context instanceof Activity) { if (!((Activity) context).isFinishing()) dialog.show(); } 

closures对话框

 if (context instanceof Activity) { if (!((Activity) context).isFinishing()) dialog.dismiss(); } 

如果你想添加更多的检查,然后添加dialog.isShowing()dialog !-null使用&&条件。

可能是你初始化pDialog全局,然后删除它,并初始化您的视图或对话本地。我有同样的问题,我已经这样做,我的问题已解决。 希望它能为你工作。

首先,崩溃的原因是decorView的索引是-1,我们可以从Android源代码中知道它,有代码片段:

等级:android.view.WindowManagerGlobal

文件:WindowManagerGlobal.java

 private int findViewLocked(View view, boolean required) { final int index = mViews.indexOf(view); //here, view is decorView,comment by OF if (required && index < 0) { throw new IllegalArgumentException("View=" + view + " not attached to window manager"); } return index; } 

所以我们得到下面的解决scheme,只是判断decorView的索引,如果它大于0则继续或只是返回并放弃解散,代码如下:

 try { Class<?> windowMgrGloable = Class.forName("android.view.WindowManagerGlobal"); try { Method mtdGetIntance = windowMgrGloable.getDeclaredMethod("getInstance"); mtdGetIntance.setAccessible(true); try { Object windownGlobal = mtdGetIntance.invoke(null,null); try { Field mViewField = windowMgrGloable.getDeclaredField("mViews"); mViewField.setAccessible(true); ArrayList<View> mViews = (ArrayList<View>) mViewField.get(windownGlobal); int decorViewIndex = mViews.indexOf(pd.getWindow().getDecorView()); Log.i(TAG,"check index:"+decorViewIndex); if (decorViewIndex < 0) { return; } } catch (NoSuchFieldException e) { e.printStackTrace(); } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } catch (NoSuchMethodException e) { e.printStackTrace(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } if (pd.isShowing()) { pd.dismiss(); }