Python отслеживает выход как аргумент функции [duplicate]

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

62
задан Martijn Pieters 21 August 2015 в 12:23
поделиться

1 ответ

Примечание: это была ошибка в обработке CPython для yield в выражениях выражений и выражений генератора, исправленных в Python 3.8, с предупреждением об отказе в Python 3.7. Смотрите отчет об ошибках Python и записи What's New для Python 3.7 и Python 3.8 .

< / blockquote>

Выражения генератора, а также функции set и dict компилируются в объекты функции (генератора). В Python 3 переписные справки получают одинаковое обращение; все они, по существу, представляют собой новую вложенную область.

Вы можете увидеть это, если попытаетесь разобрать выражение генератора:

>>> dis.dis(compile("(i for i in range(3))", '', 'exec'))
  1           0 LOAD_CONST               0 (<code object <genexpr> at 0x10f7530c0, file "", line 1>)
              3 LOAD_CONST               1 ('<genexpr>')
              6 MAKE_FUNCTION            0
              9 LOAD_NAME                0 (range)
             12 LOAD_CONST               2 (3)
             15 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             18 GET_ITER
             19 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             22 POP_TOP
             23 LOAD_CONST               3 (None)
             26 RETURN_VALUE
>>> dis.dis(compile("(i for i in range(3))", '', 'exec').co_consts[0])
  1           0 LOAD_FAST                0 (.0)
        >>    3 FOR_ITER                11 (to 17)
              6 STORE_FAST               1 (i)
              9 LOAD_FAST                1 (i)
             12 YIELD_VALUE
             13 POP_TOP
             14 JUMP_ABSOLUTE            3
        >>   17 LOAD_CONST               0 (None)
             20 RETURN_VALUE

Вышеприведенное показывает, что выражение генератора скомпилированный в объект кода, загруженный как функция (MAKE_FUNCTION создает объект функции из объекта кода). Ссылка .co_consts[0] позволяет нам видеть объект кода, сгенерированный для выражения, и использует YIELD_VALUE так же, как функция генератора.

Таким образом, выражение yield работает в этом контексте, поскольку компилятор рассматривает их как скрытые функции.

Это ошибка; yield не имеет места в этих выражениях. Python грамматика до Python 3.7 позволяет (поэтому код компилируется), но спецификация выражения yield показывает, что использование yield здесь не должно действительно работать :

Выражение yield используется только при определении функции generator и, следовательно, может использоваться только в теле определения функции.

Это было подтверждено как ошибка в выпуске 10544 . Разрешение ошибки заключается в том, что с помощью yield и yield from будет поднять SyntaxError в Python 3.8 ; в Python 3.7 он вызывает DeprecationWarning , чтобы гарантировать, что код перестает использовать эту конструкцию. Вы увидите то же предупреждение в Python 2.7.15 и выше, если вы используете переключатель командной строки -3 , включающий предупреждения о совместимости с Python 3.

Появляется предупреждение 3.7.0b1 как это; включение предупреждений в ошибки дает вам исключение SyntaxError, как и в 3.8:

>>> [(yield i) for i in range(3)]
<stdin>:1: DeprecationWarning: 'yield' inside list comprehension
<generator object <listcomp> at 0x1092ec7c8>
>>> import warnings
>>> warnings.simplefilter('error')
>>> [(yield i) for i in range(3)]
  File "<stdin>", line 1
SyntaxError: 'yield' inside list comprehension

. Различия между тем, как yield в понимании списка и yield в выражении генератора работают, вытекают из различия в том, как эти два выражения реализованы. В Python 3 в понимании списка используются вызовы LIST_APPEND, чтобы добавить верхнюю часть стека в построенный список, в то время как выражение генератора вместо этого дает это значение. Добавление в (yield <expr>) просто добавляет еще один код операции YIELD_VALUE:

>>> dis.dis(compile("[(yield i) for i in range(3)]", '', 'exec').co_consts[0])
  1           0 BUILD_LIST               0
              3 LOAD_FAST                0 (.0)
        >>    6 FOR_ITER                13 (to 22)
              9 STORE_FAST               1 (i)
             12 LOAD_FAST                1 (i)
             15 YIELD_VALUE
             16 LIST_APPEND              2
             19 JUMP_ABSOLUTE            6
        >>   22 RETURN_VALUE
>>> dis.dis(compile("((yield i) for i in range(3))", '', 'exec').co_consts[0])
  1           0 LOAD_FAST                0 (.0)
        >>    3 FOR_ITER                12 (to 18)
              6 STORE_FAST               1 (i)
              9 LOAD_FAST                1 (i)
             12 YIELD_VALUE
             13 YIELD_VALUE
             14 POP_TOP
             15 JUMP_ABSOLUTE            3
        >>   18 LOAD_CONST               0 (None)
             21 RETURN_VALUE

Код операции YIELD_VALUE в индексах байт-кода 15 и 12 соответственно является дополнительным, кукушкой в ​​гнезде. Таким образом, для генератора, использующего список, вы получаете 1 выход, каждый раз производя верхнюю часть стека (заменяя верхнюю часть стека на возвращаемое значение yield), а для варианта выражения генератора вы получаете верхнюю часть stack (целое число), а затем снова , но теперь стек содержит возвращаемое значение yield, и вы получите None второй раз.

Для списка тогда предполагается, что предполагаемый вывод объекта list все еще возвращен, но Python 3 рассматривает это как генератор, поэтому вместо этого значения возврата StopIteration в качестве атрибута value добавляется возвращаемое значение:

>>> from itertools import islice
>>> listgen = [(yield i) for i in range(3)]
>>> list(islice(listgen, 3))  # avoid exhausting the generator
[0, 1, 2]
>>> try:
...     next(listgen)
... except StopIteration as si:
...     print(si.value)
... 
[None, None, None]

Те None объекты - это возвращаемые значения из выражений yield.

И повторить это снова; эта же проблема относится к словарю и устанавливает понимание в Python 2 и Python 3; в Python 2 возвращаемые значения yield все еще добавляются к предполагаемому словарю или заданному объекту, а возвращаемое значение «дано» последнему вместо привязки к исключению StopIteration:

>>> list({(yield k): (yield v) for k, v in {'foo': 'bar', 'spam': 'eggs'}.items()})
['bar', 'foo', 'eggs', 'spam', {None: None}]
>>> list({(yield i) for i in range(3)})
[0, 1, 2, set([None])]
58
ответ дан Martijn Pieters 1 September 2018 в 02:39
поделиться
Другие вопросы по тегам:

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