"андроид.вид.WindowManager$BadTokenException: не удается добавить окно " на buider.показывать()


из моей основной деятельности, мне нужно вызвать внутренний класс и в методе внутри класса,мне нужно показать AlertDialg и уволить его, когда кнопка OK нажата и вперед в 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();
      }
    }
  }
}

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

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

7 ответов:

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

проблема :

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

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

причина :

причина этого исключения заключается в том, что, как говорится в сообщении об исключении, действие завершено, но вы пытаетесь отобразить диалоговое окно с помощью контекст завершенной деятельности. Так как нет окна для диалоговое окно для отображения среды выполнения 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();
      }
    }
  }
}

обновление :

Окне Маркеры:

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

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

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

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

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

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

if(!isFinishing())
    showDialog();

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

Эл.г

а не это.

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

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

AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();
  • во-первых, вы не можете расширить 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();
    }
    

Я создаю диалог в 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();

я заканчивал домашнюю деятельность 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();

попробуйте это :

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

}
}

С этой идеей глобальных переменных, Я сохранил экземпляр 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);
  1. Открыть MainActivity
  2. запустить поток.
  3. открыть диалог из потока - > работа.
  4. Нажмите кнопку "Назад" ( onCreate будет вызван и удален первым MainActivity)
  5. начнется новая MainActivity. (и сохраните его экземпляр в globals )
  6. открыть диалог из первого потока --> он откроется и будет работать.

:)