Объявление протокола Swift [дубликат]

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 создает специальный вид токена окна, называемый токеном окна приложения, который однозначно идентифицирует окно контейнера верхнего уровня приложения. Диспетчер активности предоставляет этот токен как для приложения, так и для диспетчера окон, и приложение отправляет токен в оконный менеджер каждый раз, когда хочет добавить на экран новое окно. Это обеспечивает безопасное взаимодействие между приложением и диспетчером окон (делая невозможным добавление окон поверх других приложений), а также упрощает диспетчеру активности непосредственные запросы к диспетчеру окон.

3
задан nhgrif 20 August 2015 в 13:34
поделиться

2 ответа

Суть ответа Starscream верна, но он пропускает , почему , который, как мне кажется, важен здесь. Это сводится к ARC и управлению памятью.

Swift - это язык ссылочных типов и типов значений. Классы являются ссылочными типами, а все остальное - типом значения. Фактически мы на самом деле не указываем, что протокол наследует от class ... это больше похоже на то, что мы указываем, что протокол может быть реализован только с помощью ссылочных типов .

И почему это важно?

Это важно, потому что без него мы не сможем использовать ключевое слово weak с протоколом.

protocol ExampleProtocol {}

class DelegatedClass {
    weak var delegate: ExampleProtocol?
}

Это порождает ошибку:

«слабый» не может применяться к неклассовому типу «ExampleProtocol»

А почему бы и нет? Поскольку ключевое слово weak имеет смысл только с ссылочными типами, к которым применяется ARC. ARC не относится к типам значений. И без указания нашего протокола с class мы не можем гарантировать, что наше свойство delegate будет присвоено ссылочному типу. (И если мы не используем weak, мы скорее всего создадим цикл сохранения.)

11
ответ дан Community 23 August 2018 в 23:17
поделиться

Из Apple docs:

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

Пример:

protocol AProtocol: class {   
}

//Following line will produce error: Non-class type 'aStruct' cannot conform to class protocol 'AProtocol'
struct aStruct: AProtocol { 
}

Строка, объявляющая структуру, выплюнет ошибку. Следующая строка вызовет ошибку:

Тип non-class 'aStruct' не может соответствовать протоколу класса AProtocol '

4
ответ дан Quill 23 August 2018 в 23:17
поделиться
Другие вопросы по тегам:

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