"android.view.WindowManager$BadTokenException: no se puede agregar la ventana" en buider.show()

Resuelto MSIslam asked hace 54 años • 11 respuestas

Desde mi main activity, necesito llamar a una clase interna y en un método dentro de la clase, necesito mostrar AlertDialog. Después de descartarlo, cuando se presione el botón Aceptar, reenvíe a Google Play para su compra.

Las cosas funcionan perfectamente la mayoría de las veces, pero para algunos usuarios falla builder.show()y puedo ver " "android.view.WindowManager$BadTokenException:No se puede agregar ventana" en el registro de fallas. Sugiera.

Mi código es más o menos así:

public class classname1 extends Activity{

  public void onCreate(Bundle savedInstanceState) {
    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
    super.onCreate(savedInstanceState);
    setContentView(R.layout.<view>); 

    //call the <className1> class to execute
  }

  private class classNamename2 extends AsyncTask<String, Void, String>{

    protected String doInBackground(String... params) {}

    protected void onPostExecute(String result){
      if(page.contains("error")) 
      {
        AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
        builder.setCancelable(true);
        builder.setMessage("");
        builder.setInverseBackgroundForced(true);
        builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int whichButton){
            dialog.dismiss();
            if(!<condition>)
            {
              try
              {
                String pl = ""; 

                mHelper.<flow>(<class>.this, SKU, RC_REQUEST, 
                  <listener>, pl);
              }

              catch(Exception e)
              {
                e.printStackTrace();
              }
            }  
          }
        });

        builder.show();
      }
    }
  }
}

También vi el error en otra alerta donde no estoy reenviando a ninguna otra activity. Es simple así:

AlertDialog.Builder builder = new AlertDialog.Builder(classname1.this);
    builder.setCancelable(true);

    //if successful
    builder.setMessage(" ");
    builder.setInverseBackgroundForced(true);
    builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton){
            // dialog.dismiss();
                   }
    });
    builder.show();
}
MSIslam avatar Jan 01 '70 08:01 MSIslam
Aceptado
android.view.WindowManager$BadTokenException: Unable to add window"

Problema :

Esta excepción ocurre cuando la aplicación intenta notificar al usuario desde el hilo en segundo plano (AsyncTask) abriendo un cuadro de diálogo.

Si está intentando modificar la interfaz de usuario desde el hilo en segundo plano (generalmente desde onPostExecute() de AsyncTask) y si la actividad entra en la etapa de finalización, es decir, llama explícitamente a finalizar(), el usuario presiona el botón de inicio o de retroceso o la limpieza de la actividad realizada por Android, entonces obtiene este error.

Razón :

El motivo de esta excepción es que, como dice el mensaje de excepción, la actividad finalizó pero usted está intentando mostrar un cuadro de diálogo con un contexto de la actividad finalizada. Dado que no hay una ventana para que el cuadro de diálogo muestre, el tiempo de ejecución de Android genera esta excepción.

Solución:

Utilice isFinishing()el método llamado por Android para verificar si esta actividad está en proceso de finalizar: ya sea una llamada explícita a Finish() o una limpieza de actividad realizada por Android. Al utilizar este método, es muy fácil evitar abrir un diálogo desde un hilo en segundo plano cuando finaliza la actividad.

También mantenga un weak referencepara la actividad (y no una referencia sólida para que la actividad pueda destruirse una vez que no sea necesaria) y verifique si la actividad no está finalizando antes de realizar cualquier interfaz de usuario usando esta referencia de actividad (es decir, mostrar un cuadro de diálogo).

p.ej .

private class chkSubscription extends AsyncTask<String, Void, String>{

  private final WeakReference<login> loginActivityWeakRef;

  public chkSubscription (login loginActivity) {
    super();
    this.loginActivityWeakRef= new WeakReference<login >(loginActivity)
  }

  protected String doInBackground(String... params) {
    //web service call
  }

  protected void onPostExecute(String result) {
    if(page.contains("error")) //when not subscribed
    {
      if (loginActivityWeakRef.get() != null && !loginActivityWeakRef.get().isFinishing()) {
        AlertDialog.Builder builder = new AlertDialog.Builder(login.this);
        builder.setCancelable(true);
        builder.setMessage(sucObject);
        builder.setInverseBackgroundForced(true);

        builder.setNeutralButton("Ok",new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog, int whichButton){
            dialog.dismiss();
          }
        });

        builder.show();
      }
    }
  }
}

Actualizar :

Fichas de ventana:

Como su nombre lo indica, un token de ventana es un tipo especial de token de Binder que el administrador de ventanas utiliza para identificar de forma única una ventana en el sistema. Los tokens de ventana son importantes para la seguridad porque hacen imposible que aplicaciones maliciosas se coloquen encima de las ventanas de otras aplicaciones. El administrador de ventanas protege contra esto al exigir que las aplicaciones pasen el token de ventana de su aplicación como parte de cada solicitud para agregar o eliminar una ventana. Si los tokens no coinciden, el administrador de ventanas rechaza la solicitud y genera una BadTokenException . Sin tokens de ventana, este paso de identificación necesario no sería posible y el administrador de ventanas no podría protegerse de aplicaciones maliciosas.

 Un escenario del mundo real:

Cuando una aplicación se inicia por primera vez,  ActivityManagerService  crea un tipo especial de token de ventana llamado token de ventana de aplicación, que identifica de forma única la ventana contenedora de nivel superior de la aplicación. El administrador de actividades proporciona este token tanto a la aplicación como al administrador de ventanas, y la aplicación envía el token al administrador de ventanas cada vez que desea agregar una nueva ventana a la pantalla. Esto garantiza una interacción segura entre la aplicación y el administrador de ventanas (al hacer imposible agregar ventanas encima de otras aplicaciones) y también facilita que el administrador de actividades realice solicitudes directas al administrador de ventanas.

Ritesh Gune avatar Sep 06 '2013 20:09 Ritesh Gune

Tenía un cuadro de diálogo que mostraba la función:

void showDialog(){
    new AlertDialog.Builder(MyActivity.this)
    ...
    .show();
}

Recibí este error y solo tenía que verificar isFinishing()antes de llamar a esta función que muestra el cuadro de diálogo.

if(!isFinishing())
    showDialog();
Jemshit avatar Aug 13 '2015 11:08 Jemshit