Есть ли ошибка в системе диспетчеризации переднего плана NFC Android?

У меня есть раздражающая проблема с поведением диспетчера переднего плана. Иногда вместо вызова onNewIntent() он полностью воссоздает активность, что нарушает рабочий процесс приложения.

Моя конкретная ситуация: Activity A – это MainActivity, которая использует диспетчеризацию переднего плана. Все работает как надо. Однако в моем действии B, которое запускается из браузера (действие VIEW), отправка переднего плана больше не работает при некоторых обстоятельствах.

Рабочий процесс:

  • Я запускаю MainActivity, переключаюсь в браузер (не закрывая MainActivity), запускаю действие B и подключаю свое устройство NFC --> оно создает новое действие B.

  • Я запускаю MainActivity и снова закрываю его. После этого я переключаюсь
    в браузер, запускаю активность B и подключаю свое устройство NFC --> все работает с onNewIntent()

Код правильный, т.е. если я дважды подключаю устройство NFC в первом сценарии, во второй раз оно работает как надо, но не в первый раз. В MainActivity и действии B я окончательно вызываю метод disableForegroundDispatch() в методе действия onPause().

Есть ли решение для моей конкретной проблемы? Для меня это звучит как ошибка.

Изменить:

public void resume(Activity targetActivity) {
    if (nfc != null && nfc.isEnabled()) {
        // nfc is the default NFC adapter and never null on my devices

        Intent intent = new Intent(targetActivity, targetActivity.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(targetActivity, 0, intent, 0);
        nfc.enableForegroundDispatch(targetActivity, pendingIntent, null, new String[][] { new String[] { IsoDep.class.getName() } });
    }
}

public void pause(Activity targetActivity) {
    if (nfc != null && nfc.isEnabled()) {
        nfc.disableForegroundDispatch(targetActivity);
    }
}

Эти методы вызываются в соответствующих методах в каждом действии. Спасибо за помощь!

Решение. После долгих поисков я наконец нашел проблему. Логкат напечатан:

  • startActivity вызывается из контекста, отличного от Activity; форсирование Intent.FLAG_ACTIVITY_NEW_TASK для: Intent

Я нашел другие проблемы в Stackoverflow, где у людей была такая же проблема с NotificationManager, но все подсказки мне не помогли. Добавление флага singleTask к моей активности B помогло мне, но, честно говоря, я этого не понимаю, потому что контекст всегда является активностью.

Я удалил весь код из MainActivity, и первый сценарий все еще не работал. Я удалил MainActivity из манифеста, и после этого все было в порядке. Может быть, проблема в том, что экземпляр приложения запущен, а активность B запускается из браузера? Я не знаю.

В любом случае, спасибо за помощь парню NFC!


person vRallev    schedule 23.04.2012    source источник
comment
Пожалуйста, покажите код созданного вами PendingIntent.   -  person NFC guy    schedule 23.04.2012
comment
Я добавил это. Заранее спасибо.   -  person vRallev    schedule 23.04.2012
comment
У меня была такая же проблема... Я решил, что вы можете использовать метод SingleTask. Я тоже не очень доволен решением. Вы нашли другой способ решить эту проблему?   -  person david    schedule 20.02.2013
comment
То же самое здесь, для меня проблема возникает, если: Main--TAG_DISCOVERED--›Активность записи с отправкой переднего плана -TAG_DISCOVERED--›Но не если: Основная активность записи с отправкой переднего плана-TAG_DISCOVERED--›   -  person Taiko    schedule 04.05.2014


Ответы (2)


IntentFilter[], которое вы передаете enableForegroundDispatch, пусто. Таким образом, ваше намерение NFC, вероятно, достигнет вашей активности из-за IntentFilter(s) в файле манифеста. Это объясняет поведение, которое вы наблюдаете, поскольку намерение NFC всегда создает новый экземпляр при доставке таким образом.

Вместо этого добавьте что-то вроде этого в свой код для включения диспетчеризации переднего плана:

IntentFilter[] iFilters = new IntentFilter[2];
iFilters[0] = new IntentFilter();
iFilters[0].addAction("android.nfc.action.TECH_DISCOVERED");
iFilters[1] = new IntentFilter();
iFilters[1].addAction("android.nfc.action.TAG_DISCOVERED");
iFilters[1].addCategory(Intent.CATEGORY_DEFAULT);

И передайте это как параметр enableForegroundDispatch.

ОБНОВЛЕНИЕ: недавно я узнал больше об этой конкретной проблеме. Это вызвано тем, как Android определяет, в какой задаче должна быть запущена новая активность. Я не знаю и не понимаю конкретных деталей того, как это работает, но эффект таков:

  1. Когда действие B запускается из браузера, оно создается в задаче браузера.
  2. Когда поступает намерение NFC, система определяет, что новое действие B должно быть создано в задаче действия A.

Из-за 2. SINGLE_TOP не игнорируется: есть только один экземпляр Activity B в верхней части задачи A. Когда действие A закрывается, его задача исчезает, поэтому действие B всегда будет создаваться в задаче браузера, как вы заметили.

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

Возможный обходной путь: объявите действие B с помощью launchMode "singleTask" (или "singleInstance"). Затем при запуске B будет создана новая (3-я) задача.

person NFC guy    schedule 23.04.2012
comment
Нет, это не помогло. Это была совершенно другая проблема (я обновил свой вопрос). Также в документе упоминается: Указание нулевого массива фильтров намерений и технологических фильтров указывает, что вы хотите фильтровать все теги, которые отступают к намерению TAG_DISCOVERED. Так что нуль должен быть в порядке в моем случае. В любом случае спасибо за помощь! - person vRallev; 23.04.2012

Я предполагаю, что ваш рабочий процесс выглядит следующим образом: Главное --> Обнаружить тег --> Читательская активность --> Писательская активность Обнаружить тег --> Записать тег

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

В частности, это не возникает, если ваш рабочий процесс выглядит следующим образом: Основная активность Writer Обнаружение тега --> Запись тега

Мой обходной путь — для начала вызвать активность писателя в новой задаче. В действии, запускающем средство записи, просто добавьте флаг новой задачи в намерение, которое запускает средство записи.

startActivity(new Intent(this,MyTagWriterActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

Главная --> Обнаружить тег --> Читательская активность -NEW_TASK-> Писательская активность Обнаружить тег --> Записать тег

Это портит историю активности, но делает активность писателя более предсказуемой.

person Taiko    schedule 04.05.2014