android - programacion - java.lang.IllegalArgumentException: vista no asociada al administrador de ventanas
manual de programacion android pdf (15)
Tengo una actividad que inicia AsyncTask y muestra el diálogo de progreso para la duración de la operación. La actividad se declara NO se recreará por rotación o diapositiva del teclado.
<activity android:name=".MyActivity"
android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation"
>
<intent-filter>
</intent-filter>
</activity>
Una vez completada la tarea, desaprovecho el diálogo, pero en algunos teléfonos (framework: 1.5, 1.6) se produce dicho error:
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)
Mi código es:
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();
Por lo que he leído ( http://bend-ing.blogspot.com/2008/11/properly-handle-progress-dialog-in.html ) y visto en las fuentes de Android, parece que la única situación posible para obtener eso excepción es cuando la actividad fue destruida. Pero como he mencionado, prohíbo actividades recreativas para eventos básicos.
Entonces, cualquier sugerencia es muy apreciada.
La actividad se declara NO se recreará por rotación o diapositiva del teclado.
Acabo de tener el mismo problema. Corrección para el nivel API 13 o superior.
De los documentos de Android:
Nota: Si su aplicación se dirige al nivel API 13 o superior (según lo declarado por los atributos minSdkVersion y targetSdkVersion), también debe declarar la configuración de "tamaño de pantalla", porque también cambia cuando un dispositivo cambia entre orientación vertical y paisaje.
Así que cambié mi manifiesto a esto:
<activity
android:name="MyActivity"
android:configChanges="orientation|screenSize"
android:label="MyActivityName" >
</activity>
Y ahora funciona bien. La actividad no se recrea cuando giro el teléfono, el diálogo de progreso y la vista permanecen igual. No hay error para mi
Antes que nada, maneje el error donde quiera que trate de cerrar el diálogo.
if ((progressDialog != null) && progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
Si eso no soluciona, deséchelo en el método onStop () de la actividad.
@Override
protected void onStop() {
super.onStop();
if ((progressDialog != null) && progressDialog.isShowing()) {
progressDialog.dismiss();
progressDialog = null;
}
}
Aquí está la solución correcta para resolver este problema:
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;
}
}
En lugar de atrapar ciegamente todas las excepciones, esta solución aborda la raíz del problema: tratar de borrar un diálogo cuando la actividad utilizada para inicializar el diálogo ya ha finalizado. Trabajando en mi Nexus 4 corriendo KitKat, pero debería funcionar para todas las versiones de Android.
Aquí está mi solución "a prueba de balas", que es la compilación de todas las buenas respuestas que encontré sobre este tema (gracias a @Damjan y @Kachi). Aquí la excepción se traga solo si todas las otras formas de detección no tuvieron éxito. En mi caso, necesito cerrar el diálogo automáticamente y esta es la única forma de proteger la aplicación del bloqueo. ¡Espero que te ayude! Por favor, vote y deje comentarios si tiene comentarios o una mejor solución. ¡Gracias!
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;
}
}
Creo que su código es correcto a diferencia de la otra respuesta sugerida. onPostExecute se ejecutará en el hilo de UI. Ese es el objetivo de AsyncTask: no tiene que preocuparse por llamar a runOnUiThread o tratar con los manejadores. Además, de acuerdo con los documentos, dismiss () se puede llamar de forma segura desde cualquier hilo (no estoy seguro de que esto sea la excepción).
Quizás es un problema de tiempo cuando se llama a dialog.dismiss () una vez que la actividad ya no se muestra.
¿Qué tal probar lo que sucede si se comenta el setOnCancelListener y luego se sale de la actividad mientras se ejecuta la tarea en segundo plano? Entonces su onPostExecute intentará descartar un diálogo ya descartado. Si la aplicación falla, probablemente solo puedas verificar si el diálogo está abierto antes de descartarlo.
Estoy teniendo exactamente el mismo problema, así que voy a probarlo en código.
El código de Migh a continuación funciona para usted. Funciona perfectamente para mí:
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();
}
}
No defina su vista globalmente si la llama desde el servicio en segundo plano.
Es posible que tenga una solución.
Estaba teniendo el mismo problema, donde estoy cargando muchos elementos (a través del sistema de archivos) en un ListView
través de AsyncTask
. Tenía onPreExecute()
un ProgressDialog
, y luego onPostExecute()
y onCancelled()
(llamado cuando la tarea se cancela explícitamente a través de AsyncTask.cancel()
) cerrándola a través de .cancel()
.
Obtuve el mismo error "java.lang.IllegalArgumentException: View not attached to window manager" cuando estaba matando el diálogo en el método onCancelled()
de AsyncTask
(lo había visto en la excelente aplicación Shelves ).
La solución fue crear un campo público en AsyncTask
que contiene el ProgressDialog
:
public ProgressDialog mDialog;
Luego, en onDestroy()
cuando cancele mi AsyncTask
, también puedo eliminar el diálogo asociado a través de:
AsyncTask.mDialog.cancel();
Llamar a AsyncTask.cancel()
onCancelled()
en AsyncTask
, pero por alguna razón en el momento en que se llama a ese método, la Vista ya se ha destruido y, por lo tanto, cancela el diálogo que está fallando.
Estoy de acuerdo con la opinión de ''Damjan''.
si usa muchos cuadros de diálogo, debe cerrar todos los cuadros de diálogo en Destroy () o onStop ().
entonces es posible que pueda reducir la frecuencia en la que se produce la excepción ''java.lang.IllegalArgumentException: View not attached to window manager''.
@Override
protected void onDestroy() {
Log.d(TAG, "called onDestroy");
mDialog.dismiss();
super.onDestroy();
}
pero poco más ...
para hacerlo más claro, evita mostrar ningún cuadro de diálogo después de llamar a onDestroy.
no uso como abajo pero está claro.
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();
}
¡buena suerte!
Lo que funcionó para mí la mayor parte del tiempo es verificar si la actividad no está terminando.
if (!mActivity.isFinishing()) {
dialog.dismiss();
}
Tuve el mismo problema al usar un botón para sincronizar una lista del servidor: 1) hago clic en el botón 2) Aparece un cuadro de diálogo de progreso mientras descargo la lista del servidor 3) Giro el dispositivo a otra orientación 4) java.lang .IllegalArgumentException: vista no asociada al administrador de ventanas en postExecute () de AsyncTask durante progress.dismiss ().
Cuando probé la solución, pensé que, incluso si el problema no ocurría, mi lista no mostraba todos los elementos.
Pensé que lo que quería era que AsyncTask finalizara (y descartara el diálogo) antes de que se destruyera la actividad, por lo que convertí el objeto asynctask en un atributo y anulé el método onDestroy ().
Si la asynctask toma mucho tiempo, el usuario puede sentir que el dispositivo es lento, pero creo que ese es el precio que paga por tratar de cambiar la orientación del dispositivo mientras se muestra el diálogo de progreso. E incluso si lleva algo de tiempo, la aplicación no falla.
private AsyncTask<Boolean, Void, Boolean> atask;
@Override
protected void onDestroy() {
if (atask!=null)
try {
atask.get();
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
super.onDestroy();
}
Tuve el mismo problema, puedes resolverlo de la siguiente manera:
@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;
}
}
Utilizar esta.
if(_dialog!=null && _dialog.isShowing()) _dialog.dismiss();
Yo también recibo este error a veces cuando dejo de dialogar y termino la actividad del método onPostExecute. Supongo que a veces la actividad finaliza antes de que el diálogo finalice exitosamente.
Solución simple pero efectiva que funciona para mí
@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;
}
}
alex,
Podría estar equivocado aquí, pero sospecho que varios teléfonos "en la naturaleza" tienen un error que les hace cambiar de orientación en las aplicaciones que están marcadas como estáticamente orientadas. Esto sucede bastante en mi teléfono personal y en muchos de los teléfonos de prueba que usa nuestro grupo (incluidos droides, n1, g1, héroes). Normalmente, una aplicación marcada como estáticamente orientada (quizás verticalmente) se extenderá durante uno o dos segundos utilizando una orientación horizontal, y luego volverá inmediatamente. El resultado final es que, aunque no desee que su aplicación cambie de orientación, debe estar preparado para hacerlo. No sé bajo qué condiciones exactas se puede reproducir este comportamiento, no sé si es específico de una versión de Android. Todo lo que sé es que lo he visto suceder muchas veces :(
Recomendaría utilizar la solución provista http://bend-ing.blogspot.com/2008/11/properly-handle-progress-dialog-in.html que sugiere anular el método Activity onCreateDialog y permitir que el SO Android administre el ciclo de vida de sus Diálogos. Me parece que aunque no quieras que tu actividad cambie de orientación, está cambiando de orientación en alguna parte. Puede intentar rastrear un método que siempre evitará el cambio de orientación, pero estoy tratando de decirle que personalmente no creo que exista una forma infalible que funcione en todos los teléfonos Android actuales en el mercado.
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (progressDialog != null && progressDialog.isShowing()) {
Log.i(TAG, "onPostexucte");
progressDialog.dismiss();
}
}