"android.view.WindowManager $BadTokenException: невозможно добавить окно" на buider.show()

Из моего основного activity мне нужно вызвать внутренний класс, а в методе внутри класса мне нужно показать AlertDialog. После его закрытия, когда нажата кнопка ОК, переходим в Google Play для покупки.

В большинстве случаев все работает идеально, но для немногих пользователей происходит сбой на builder.show(), и я вижу "android.view.WindowManager$BadTokenException: Невозможно добавить окно "из журнала сбоев. Пожалуйста, предложите.

Мой код очень похож на это:

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();
      }
    }
  }
}

Я также видел ошибку в другом предупреждении, когда я не пересылаю ни в какой другой activity. Это просто так:

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();
}

Ответ 1

android.view.WindowManager$BadTokenException: Unable to add window"

Проблема:

Это исключение возникает, когда приложение пытается уведомить пользователя из фоновый поток (AsyncTask), открыв диалоговое окно.

Если вы пытаетесь изменить пользовательский интерфейс из фонового потока (обычно из onPostExecute() AsyncTask), и если действие входит в завершающий этап i.e.), явно вызывающий финиш(), нажатие на пользователя или кнопку "Назад" или очистка активности, сделанные Android, тогда вы получите это ошибка.

Причина:

Причиной этого исключения является то, что, как говорится в сообщении об исключении, действие завершено, но вы пытаетесь отобразить диалог с контекст готовой деятельности. Поскольку нет окна для диалоговое окно для отображения времени выполнения андроида вызывает это исключение.

Решение:

Использовать метод isFinishing(), который вызывается Android для проверки того, эта деятельность находится в процессе отделки: будь то явная обработка() звонка или активности, сделанных Android. Используя этот метод, очень легко избежать открытия диалога из фонового потока, когда активность заканчивается.

Также поддерживайте weak reference для активности (и не сильный ссылку, чтобы активность могла быть уничтожена, когда это не было необходимо) и проверьте если активность не заканчивается, прежде чем выполнять какой-либо пользовательский интерфейс, используя этот (т.е. показывая диалог).

например,.

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();
      }
    }
  }
}

Обновление:

Токены окна:

Как следует из его названия, токен окна - это особый тип токена Binder что диспетчер окон использует уникальную идентификацию окна в система. Ярлыки окна важны для безопасности, потому что они делают это невозможно, чтобы вредоносные приложения рисовали поверх окон других приложений. Менеджер окон защищает это от требуя, чтобы приложения передавали свой токен окна приложения как часть каждого запроса для добавления или удаления окна. Если токены не match, оконный менеджер отклоняет запрос и бросает BadTokenException. Без оконных жетонов это необходимо шаг идентификации был бы невозможным, а диспетчер окон не сможет защитить себя от вредоносных приложений.

Реальный сценарий:

Когда приложение запускается в первый раз, ActivityManagerService создает специальный вид токена окна называемый токеном окна приложения, который однозначно идентифицирует окно верхнего уровня приложения. Менеджер активности дает этот токен как для приложения, так и для диспетчера окон, и приложение посылает маркер в оконный менеджер каждый раз, когда он хочет для добавления нового окна на экран. Это обеспечивает безопасное взаимодействие между приложением и менеджером окон (путем создания невозможно добавить окна поверх других приложений), а также упрощает диспетчеру активности прямые запросы к оконный менеджер.

Ответ 2

У меня был диалог, показывающий функцию:

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

Я получал эту ошибку, и мне просто нужно было проверить isFinishing() перед вызовом этого диалогового окна, показывающего функцию.

if(!isFinishing())
    showDialog();

Ответ 3

Возможная причина - контекст диалогового окна предупреждения. Вы можете завершить эту деятельность, чтобы ее попытка открыть в этом контексте, но которая уже закрыта. Попытайтесь изменить контекст этого диалога на первую операцию, потому что она не будет закончена до конца.

e.g

вместо этого.

AlertDialog alertDialog = new AlertDialog.Builder(this).create();

попробуйте использовать

AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();

Ответ 4

  • сначала вы не можете расширить AsyncTask без переопределения doInBackground
  • попробуйте создать AlterDailog из конструктора, затем вызовите show().

    private boolean visible = false;
    class chkSubscription extends AsyncTask<String, Void, String>
    {
    
        protected void onPostExecute(String result)
        {
            AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.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();
                }
            });
    
            AlertDialog myAlertDialog = builder.create();
            if(visible) myAlertDialog.show();
        }
    
        @Override
        protected String doInBackground(String... arg0)
        {
            // TODO Auto-generated method stub
            return null;
        }
    }
    
    
    @Override
    protected void onResume()
    {
        // TODO Auto-generated method stub
        super.onResume();
        visible = true;
    }
    
    @Override
    protected void onStop()
    {
        visible = false; 
        super.onStop();
    }
    

Ответ 5

Я создаю диалог в onCreate и использую его с show и hide. Для меня первопричина не отклоняла onBackPressed, которая заканчивала действие Home.

@Override
public void onBackPressed() {
new AlertDialog.Builder(this)
                .setTitle("Really Exit?")
                .setMessage("Are you sure you want to exit?")
                .setNegativeButton(android.R.string.no, null)
                .setPositiveButton(android.R.string.yes,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                Home.this.finish();
                                return;
                            }
                        }).create().show();

Я закончил Home Activity onBackPressed, не закрывая/отклоняя мои диалоги.

Когда я отклонил мои диалоги, авария исчезла.

new AlertDialog.Builder(this)
                .setTitle("Really Exit?")
                .setMessage("Are you sure you want to exit?")
                .setNegativeButton(android.R.string.no, null)
                .setPositiveButton(android.R.string.yes,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                    int which) {
                                networkErrorDialog.dismiss() ;
                                homeLocationErrorDialog.dismiss() ;
                                currentLocationErrorDialog.dismiss() ;
                                Home.this.finish();
                                return;
                            }
                        }).create().show();

Ответ 6

Я пытаюсь это решить.

 AlertDialog.Builder builder = new AlertDialog.Builder(
                   this);
            builder.setCancelable(true);
            builder.setTitle("Opss!!");

            builder.setMessage("You Don't have anough coins to withdraw. ");
            builder.setMessage("Please read the Withdraw rules.");
            builder.setInverseBackgroundForced(true);
            builder.setPositiveButton("OK",
                    (dialog, which) -> dialog.dismiss());
            builder.create().show();

Ответ 7

Попробуйте следующее:

    public class <class> extends Activity{

    private AlertDialog.Builder builder;

    public void onCreate(Bundle savedInstanceState) {
                    this.requestWindowFeature(Window.FEATURE_NO_TITLE);
                    super.onCreate(savedInstanceState);

                setContentView(R.layout.<view>); 

                builder = new AlertDialog.Builder(<class>.this);
                builder.setCancelable(true);
                builder.setMessage(<message>);
                builder.setInverseBackgroundForced(true);

        //call the <className> class to execute
}

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

    protected String doInBackground(String... params) {

    }
    protected void onPostExecute(String result){
        if(page.contains("error")) //when not subscribed
        {   
           if(builder!=null){
                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();
        }
    }

}
}

Ответ 8

AlertDialog.Builder builder = new AlertDialog.Builder(Activity.this);
builder.setTitle("Invalid Data");
builder.setMessage("please enter valid name and mobile no.");
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
    public void onClick(DialogInterface dialog, int id) {
        dialog.cancel ();
    }
});
AlertDialog alertDialog = builder.create();
alertDialog.show();

Ответ 9

с этой идеей глобальных переменных, Я сохранил экземпляр MainActivity в onCreate(); Глобальная переменная Android

public class ApplicationController extends Application {

    public static MainActivity this_MainActivity;
}

и открыть диалоговое окно, подобное этому. он работал.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Global Var
    globals = (ApplicationController) this.getApplication();
    globals.this_MainActivity = this;
}

и в потоке я открываю диалоговое окно, подобное этому.

AlertDialog.Builder alert = new AlertDialog.Builder(globals.this_MainActivity);
  • Открыть MainActivity
  • Начать поток.
  • Откройте диалог из потока → работа.
  • Нажмите кнопку "Назад" (onCreate будет вызываться и удалить первую MainActivity).
  • Запустится новая MainActivity. (и сохраните его экземпляр в глобальные).
  • Откройте диалог из первого потока → он откроется и будет работать.

:)