android View not attached to window manager
I am having some of the following exceptions:
java.lang.IllegalArgumentException: View not attached to window manager
at android.view.WindowManagerImpl.findViewLocked(WindowManagerImpl.java:355)
at android.view.WindowManagerImpl.updateViewLayout(WindowManagerImpl.java:191)
at android.view.Window$LocalWindowManager.updateViewLayout(Window.java:428)
at android.app.Dialog.onWindowAttributesChanged(Dialog.java:596)
at android.view.Window.setDefaultWindowFormat(Window.java:1013)
at com.android.internal.policy.impl.PhoneWindow.access$700(PhoneWindow.java:86)
at com.android.internal.policy.impl.PhoneWindow$DecorView.drawableChanged(PhoneWindow.java:1951)
at com.android.internal.policy.impl.PhoneWindow$DecorView.fitSystemWindows(PhoneWindow.java:1889)
at android.view.ViewRoot.performTraversals(ViewRoot.java:727)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1633)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4338)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.a开发者_运维问答ndroid.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method)
I have googled it and see that it has something to do with popups and turning the screen, but there is no reference to my code.
The questions are:
- is there a way to find out exactly when this issue is happening?
- other than turning the screen, is there another event or action that triggers this error?
- how do I prevent this to happen?
I had this issue where on a screen orientation change, the activity finished before the AsyncTask with the progress dialog completed. I seemed to resolve this by setting the dialog to null onPause()
and then checking this in the AsyncTask before dismissing.
@Override
public void onPause() {
super.onPause();
if ((mDialog != null) && mDialog.isShowing())
mDialog.dismiss();
mDialog = null;
}
... in my AsyncTask:
protected void onPreExecute() {
mDialog = ProgressDialog.show(mContext, "", "Saving changes...",
true);
}
protected void onPostExecute(Object result) {
if ((mDialog != null) && mDialog.isShowing()) {
mDialog.dismiss();
}
}
After a fight with this issue, I finally end up with this workaround:
/**
* Dismiss {@link ProgressDialog} with check for nullability and SDK version
*
* @param dialog instance of {@link ProgressDialog} to dismiss
*/
public void dismissProgressDialog(ProgressDialog dialog) {
if (dialog != null && 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 (!((Activity) context).isFinishing() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (!((Activity) context).isDestroyed()) {
dismissWithExceptionHandling(dialog);
}
} else {
// Api < 17. Unfortunately cannot check for isDestroyed()
dismissWithExceptionHandling(dialog);
}
}
} else
// if the Context used wasn't an Activity, then dismiss it too
dismissWithExceptionHandling(dialog);
}
dialog = null;
}
}
/**
* Dismiss {@link ProgressDialog} with try catch
*
* @param dialog instance of {@link ProgressDialog} to dismiss
*/
public void dismissWithExceptionHandling(ProgressDialog dialog) {
try {
dialog.dismiss();
} catch (final IllegalArgumentException e) {
// Do nothing.
} catch (final Exception e) {
// Do nothing.
} finally {
dialog = null;
}
}
Sometimes, good exception handling works well if there wasn't a better solution for this issue.
If you have an Activity
object hanging around, you can use the isDestroyed()
method:
Activity activity;
// ...
if (!activity.isDestroyed()) {
// ...
}
This is nice if you have a non-anonymous AsyncTask
subclass that you use in various places.
I am using a custom static class which makes- shows and hides a dialog. this class is being used by other activities too not only one activiy. Now the problem you described also appeared to me and i have stayed overnight to find a solution..
Finally i present you the solution!
if you want to show or dismiss a dialog and you dont know which activity initiated the dialog in order to touch it then the following code is for you..
static class CustomDialog{
public static void initDialog(){
...
//init code
...
}
public static void showDialog(){
...
//init code for show dialog
...
}
/****This is your Dismiss dialog code :D*******/
public static void dismissProgressDialog(Context context) {
//Can't touch other View of other Activiy..
//http://stackoverflow.com/questions/23458162/dismiss-progress-dialog-in-another-activity-android
if ( (progressdialog != null) && progressdialog.isShowing()) {
//is it the same context from the caller ?
Log.w("ProgressDIalog dismiss", "the dialog is from"+progressdialog.getContext());
Class caller_context= context.getClass();
Activity call_Act = (Activity)context;
Class progress_context= progressdialog.getContext().getClass();
Boolean is_act= ( (progressdialog.getContext()) instanceof Activity )?true:false;
Boolean is_ctw= ( (progressdialog.getContext()) instanceof ContextThemeWrapper )?true:false;
if (is_ctw) {
ContextThemeWrapper cthw=(ContextThemeWrapper) progressdialog.getContext();
Boolean is_same_acivity_with_Caller= ((Activity)(cthw).getBaseContext() == call_Act )?true:false;
if (is_same_acivity_with_Caller){
progressdialog.dismiss();
progressdialog = null;
}
else {
Log.e("ProgressDIalog dismiss", "the dialog is NOT from the same context! Can't touch.."+((Activity)(cthw).getBaseContext()).getClass());
progressdialog = null;
}
}
}
}
}
Above solution didn't work for me. So what I did is take ProgressDialog
as globally and then add this to my activity
@Override
protected void onDestroy() {
if (progressDialog != null && progressDialog.isShowing())
progressDialog.dismiss();
super.onDestroy();
}
so that in case if activity is destroyed then the ProgressDialog will also be destroy.
For question 1):
Considering that the error message doesn't seem to say which line of your code is causing the trouble, you can track it down by using breakpoints. Breakpoints pause the execution of the program when the program gets to specific lines of code. By adding breakpoints to critical locations, you can determine which line of code causes the crash. For example, if your program is crashing at a setContentView() line, you could put a breakpoint there. When the program runs, it will pause before running that line. If then resuming causes the program to crash before reaching the next breakpoint, you then know that the line that killed the program was between the two breakpoints.
Adding breakpoints is easy if you're using Eclipse. Right click in the margin just to the left of your code and select "Toggle breakpoint". You then need to run your application in debug mode, the button that looks like a green insect next to the normal run button. When the program hits a breakpoint, Eclipse will switch to the debug perspective and show you the line it is waiting at. To start the program running again, look for the 'Resume' button, which looks like a normal 'Play' but with a vertical bar to the left of the triangle.
You can also fill your application with Log.d("My application", "Some information here that tells you where the log line is"), which then posts messages in Eclipse's LogCat window. If you can't find that window, open it up with Window -> Show View -> Other... -> Android -> LogCat.
Hope that helps!
I added the following to the manifest for that activity
android:configChanges="keyboardHidden|orientation|screenLayout"
according to the code of the windowManager (link here), this occurs when the view you are trying to update (which probably belongs to a dialog, but not necessary) is no longer attached to the real root of the windows.
as others have suggested, you should check the status of the activity before performing special operations on your dialogs.
here's the relavant code, which is the cause to the problem (copied from Android source code) :
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}
final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;
view.setLayoutParams(wparams);
synchronized (this) {
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots[index];
mParams[index] = wparams;
root.setLayoutParams(wparams, false);
}
}
private int findViewLocked(View view, boolean required) {
synchronized (this) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i<count; i++) {
if (mViews[i] == view) {
return i;
}
}
if (required) {
throw new IllegalArgumentException(
"View not attached to window manager");
}
return -1;
}
}
My problem was solved by uhlocking the screen rotation on my android the app which was causing me a problem now works perfectly
Another option is not to start the async task until the dialog is attached to the window by overriding onAttachedToWindow() on the dialog, that way it is always dismissible.
Or Simply you Can add
protected void onPreExecute() {
mDialog = ProgressDialog.show(mContext, "", "Saving changes...", true, false);
}
which will make the ProgressDialog
to not cancel-able
Why not try catch, like this:
protected void onPostExecute(Object result) {
try {
if ((mDialog != null) && mDialog.isShowing()) {
mDialog.dismiss();
}
} catch (Exception ex) {
Log.e(TAG, ex.getMessage(), ex);
}
}
when you declare activity in the manifest you need android:configChanges="orientation"
example:
<activity android:theme="@android:style/Theme.Light.NoTitleBar" android:configChanges="orientation" android:label="traducción" android:name=".PantallaTraductorAppActivity"></activity>
精彩评论