视图不附加到窗口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>
我错过了什么来阻止这次事故的发生?
如何重现该错误:
- 在您的设备上启用此选项:
Settings -> Developer Options -> Don't keep Activities
。 - 当
AsyncTask
正在执行并显示ProgressDialog
时,请按Homebutton。
Android操作系统一旦隐藏就会摧毁一个活动。 当onPostExecute
被调用时, Activity
将处于“完成”状态, ProgressDialog
将不会附加到Activity
。
如何解决它:
- 检查
onPostExecute
方法中的活动状态。 - closures
onDestroy
方法中的ProgressDialog
。 否则,会抛出android.view.WindowLeaked
exception。 这个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); } } }
问题可能是Activity
已finished
或progress 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 manager
exception。
示例代码
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种方法可以解决这个问题:
- @ erakitin的回答:调用
isFinishing()
来检查活动的状态 - @Kapé的回答:设置标志来检查活动的状态
- 使用try / catch来处理它。
- 在
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(); }