Ошибка приложения, WindowManager $ BadTokenException [дубликат]

В дополнение к объяснению Martijn :

Функция уровня модуля - это функция, которая определена на уровне модуля, что означает, что это не метод экземпляра класса, он не вложен в другую функцию и является «реальной» функцией с именем, а не с лямбда-функцией.

Итак, чтобы разжечь ваш defaultdict, создайте его с помощью функции уровня модуля вместо лямбда-функция:

def dd():
    return defaultdict(int)

dict1 = defaultdict(dd) # dd is a module-level function

, чем вы можете ее рассортировать

tmp = pickle.dumps(dict1) # no exception
new = pickle.loads(tmp)

78
задан hendrathings 1 April 2018 в 04:05
поделиться

7 ответов

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

Проблема:

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

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

Причина:

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

Решение:

Использовать метод 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, который оконный менеджер использует для уникальной идентификации окна в системе. Ярлыки окна важны для безопасности, потому что они делают невозможным использование вредоносных приложений поверх окон других приложений. Менеджер окон защищает от этого, требуя от приложений передать токен своего приложения как часть каждого запроса на добавление или удаление окна. Если жетоны не совпадают, диспетчер окон отклоняет запрос и генерирует исключение BadTokenException. Без токенов окна этот необходимый шаг идентификации не был бы возможен, и оконный менеджер не смог бы защитить себя от вредоносных приложений.

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

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

208
ответ дан Ritesh Gune 17 August 2018 в 13:07
поделиться
  • 1
    Это имеет большой смысл! Также ваше решение отлично подходит для меня. (У) – MSIslam 6 September 2013 в 21:20
  • 2
    это решило вашу проблему? – Ritesh Gune 6 September 2013 в 21:28
  • 3
    'Пустое конечное поле loginActivityWeakRef, возможно, не было инициализировано', и попытался таким образом: private final WeakReference & lt; login & gt; loginActivityWeakRef = new WeakReference & lt; login & gt; (login.this); не уверен, правильно ли это делать – MSIslam 6 September 2013 в 21:31
  • 4
    Также я удалил финал до WeakReference & lt; login & gt; loginActivityWeakRef, поскольку он показывал ошибку в конструкторе. – MSIslam 6 September 2013 в 21:37
  • 5
    попробуйте использовать новую chkCubscription (this) .execute (& quot;); вместо нового chkCubscription.execute (& quot;); как вы писали выше. – Ritesh Gune 6 September 2013 в 21:48

с этой идеей глобальных переменных, я сохранил экземпляр 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. Открыть диалог из потока -> work.
  4. Нажмите кнопку «Назад» (onCreate будет вызываться и удалить первую MainActivity)
  5. Запустится новая MainActivity. (и сохраните его экземпляр для глобалов)
  6. Откройте диалог из первого потока -> он откроется и будет работать.

:)

-4
ответ дан Community 17 August 2018 в 13:07
поделиться
  • 1
    Никогда не ставьте ссылку на активность. Это приведет к утечке памяти – Leandroid 3 April 2017 в 20:06

У меня был диалог с функцией:

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

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

if(!isFinishing())
    showDialog();
15
ответ дан Jemshit Iskenderov 17 August 2018 в 13:07
поделиться
  • 1
    не следует ли писать if(!MyActivity.this.isFinishing())? Если это неверно в MyActivity – Bibaswann Bandyopadhyay 14 January 2017 в 11:29

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

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

}
}
0
ответ дан pathe.kiran 17 August 2018 в 13:07
поделиться

Я создаю диалог в 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();
0
ответ дан Siddharth 17 August 2018 в 13:07
поделиться
  • сначала вы не можете расширять 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();
    }
    
3
ответ дан Tony_A 17 August 2018 в 13:07
поделиться
  • 1
    Спасибо за ответ. Я действительно использовал метод doInBackground, просто не упоминал об этом здесь, поскольку он не связан с предупреждением. Что касается добавления builder.create (), кажется, что он работает нормально, но не знаю, будет ли он работать нормально для всех. Как я уже говорил ранее, мой текущий код также отлично работает, но только несколько раз для нескольких пользователей он показывает, что не удалось добавить проблему с окном. Не могли бы вы предложить мне, что может быть актуальной проблемой в моем кодировании, что может вызвать это? – MSIslam 6 September 2013 в 18:56
  • 2
    в этом случае пользователь выходит из вашей активности до вызова onPostExecute, поэтому нет окна для хранения диалогового окна, и это приводит к сбою приложения. добавьте флаг в onStop, чтобы узнать, не видна ли ваша активность, а затем не показывать диалог. – moh.sukhni 6 September 2013 в 19:01
  • 3
    onPostExecute фактически вызывается, поскольку builder.show () находится под условием, когда я проверяю, не подписан ли пользователь на основе результата вызова веб-службы из doInBackground (). Поэтому, если onPostExecute не был вызван, он не попал бы в строку builder.show (). – MSIslam 6 September 2013 в 20:48
  • 4
    onPostExecute вызывается по умолчанию после doInBackground, вы не можете его вызывать и что когда-либо будет выполнено. – moh.sukhni 6 September 2013 в 21:00
  • 5
    ваша задача async продолжит работу после того, как пользователь перейдет из вашей активности, и это приведет к тому, что builder.show () будет разорвать ваше приложение, потому что нет никакой активности для обработки пользовательского интерфейса. поэтому ваше приложение извлекает данные из Интернета, но ваша деятельность была уничтожена до того, как вы получите данные. – moh.sukhni 6 September 2013 в 21:10

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

, например

, а не это.

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

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

AlertDialog alertDialog = new AlertDialog.Builder(FirstActivity.getInstance()).create();
9
ответ дан Ziem 17 August 2018 в 13:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: