PendingIntent работает правильно для первого уведомления, но неправильно для остальных - PullRequest
82 голосов
/ 02 июля 2010
  protected void displayNotification(String response) {
    Intent intent = new Intent(context, testActivity.class);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

    Notification notification = new Notification(R.drawable.icon, "Upload Started", System.currentTimeMillis());
    notification.setLatestEventInfo(context, "Upload", response, pendingIntent);

    nManager.notify((int)System.currentTimeMillis(), notification);
}

Эта функция будет вызываться несколько раз.Я бы хотел, чтобы каждый notification запускал testActivity при нажатии.К сожалению, только первое уведомление запускает testActivity.Нажатие на остальное приводит к сворачиванию окна уведомлений.

Дополнительная информация: Функция displayNotification() находится в классе с именем UploadManager.Context передается в UploadManager от activity, который создает экземпляр.Функция displayNotification() вызывается несколько раз из функции, также в UploadManager, которая выполняется в AsyncTask.

Редактировать 1: я забыл упомянуть, что передаю строковый ответ в Intent intent какextra.

  protected void displayNotification(String response) {
    Intent intent = new Intent(context, testActivity.class);
    intent.putExtra("response", response);
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

Это имеет большое значение, потому что мне нужен дополнительный «ответ», чтобы отразить, какой был ответ String при создании уведомления.Вместо этого, используя PendingIntent.FLAG_UPDATE_CURRENT, дополнительный «ответ» отражает ответ String на последний вызов displayNotification().

Я знаю, почему это происходит из чтения документации по FLAG_UPDATE_CURRENT.Тем не менее, я не уверен, как обойти это в данный момент.

Ответы [ 13 ]

110 голосов
/ 02 июля 2010

Не используйте Intent.FLAG_ACTIVITY_NEW_TASK для PendingIntent.getActivity, используйте FLAG_ONE_SHOT вместо


Скопировано из комментариев:

Тогдаустановите какое-либо фиктивное действие на Intent, в противном случае дополнительные функции будут сброшены.Например

intent.setAction(Long.toString(System.currentTimeMillis()))
58 голосов
/ 03 февраля 2012

боролся с RemoteViews и несколькими разными Intents для каждого Button на HomeScreen виджете.Сработало при добавлении этих:

1. intent.setAction(Long.toString(System.currentTimeMillis()));

2. PendingIntent.FLAG_UPDATE_CURRENT

        PackageManager pm = context.getPackageManager();

        Intent intent = new Intent(context, MyOwnActivity.class);
        intent.putExtra("foo_bar_extra_key", "foo_bar_extra_value");
        intent.setAction(Long.toString(System.currentTimeMillis()));
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        RemoteViews views = new RemoteViews(context.getPackageName(),
                R.layout.widget_layout);
        views.setOnClickPendingIntent(my_button_r_id_received_in_parameter, pendingIntent);
40 голосов
/ 05 июля 2014

Set Action Решил это для меня. Вот мое понимание ситуации:


У меня есть несколько виджетов, к которым прикреплен PendingIntent. Всякий раз, когда один обновлялся, они все обновлялись. Флаги предназначены для описания того, что происходит с PendingIntents, которые в точности совпадают.

FLAG_UPDATE_CURRENT теперь выглядит намного лучше:

Если тот же PendingIntent, который вы делаете, уже существует, то обновите все старые до нового PendingIntent, который вы делаете.

Определение точно так же смотрится на весь PendingIntent, КРОМЕ ЛОГОТИПОВ. Таким образом, даже если у вас есть разные дополнения для каждого намерения (для меня я добавил appWidgetId), то для Android они одинаковы.

Добавление .setAction с какой-то фиктивной уникальной строкой сообщает ОС. Они совершенно разные и ничего не обновляют. В конце, вот моя реализация, которая работает так, как я хотел, где каждый виджет имеет свою собственную настройку Intent:

Intent configureIntent = new Intent(context, ActivityPreferences.class);

configureIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);

configureIntent.setAction("dummy_unique_action_identifyer" + appWidgetId);

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, configureIntent,
    PendingIntent.FLAG_UPDATE_CURRENT);

UPDATE


Еще лучшее решение, если вы работаете с трансляциями. Уникальные PendingIntents также определяются уникальными кодами запросов. Вот мое решение:

//Weee, magic number, just want it to be positive nextInt(int r) means between 0 and r
int dummyuniqueInt = new Random().nextInt(543254); 
PendingIntent pendingClearScreenIntent = PendingIntent.getBroadcast(context, 
    dummyuniqueInt, clearScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
13 голосов
/ 22 июня 2017

Я вижу ответы, но без объяснений. Также ни один из ответов не касается всех возможных решений, поэтому я постараюсь прояснить это.

Документация:

Если вам действительно нужно, чтобы несколько отдельных объектов PendingIntent были активны одновременно (например, для использования в качестве двух уведомлений, которые отображаются одновременно), вам необходимо убедиться, что в них есть что-то отличное, чтобы связать их. их с разными PendingIntents. Это может быть любой из атрибутов Intent, рассматриваемых Intent.filterEquals, или различные целые числа кода запроса, предоставленные для getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int , Intent, int) или getService (Context, int, Intent, int).

Причина проблемы:

Вы создаете 2 уведомления с 2 ожидающими намерениями. Каждое ожидающее намерение связано с намерением:

Intent intent = new Intent(context, testActivity.class);

Однако эти 2 намерения равны, поэтому, когда придет ваше второе уведомление, оно запустит первое намерение.

Решение:

Вы должны сделать каждое намерение уникальным, чтобы никакие ожидающие намерения никогда не были равны. Как вы делаете намерения уникальными? Не из дополнений, которые вы ставите с putExtra(). Даже если дополнения разные, намерения все равно могут быть одинаковыми. Чтобы сделать каждое намерение уникальным, вы должны установить уникальное значение для действия намерения, или данных, или типа, или класса, или категории, или кода запроса: (любой из них будет работать)

  • действие: intent.setAction(...)
  • данные: intent.setData(...)
  • тип: intent.setType(...)
  • класс: intent.setClass(...)
  • категория: intent.addCategory(...)
  • код запроса: PendingIntent.getActivity(context, YOUR_UNIQUE_CODE, intent, Intent.FLAG_ONE_SHOT);

Примечание : Установка уникального кода запроса может быть непростой задачей, потому что вам нужен int, а System.currentTimeMillis() возвращает long, что означает, что некоторые цифры будут удалены. Поэтому я бы рекомендовал либо перейти с category или action и установить уникальную строку.

13 голосов
/ 02 июля 2010

У меня была такая же проблема, и я смог ее исправить, изменив флаг на:

PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
9 голосов
/ 08 января 2015

Как указано в документации, используйте уникальный код запроса:

Если вам действительно нужно, чтобы несколько отдельных объектов PendingIntent были активными одновременно (например, для использования в качестве двух уведомлений, которые оба отображаются одновременно)тогда вам нужно убедиться, что в них есть что-то отличающееся, чтобы связать их с разными PendingIntents.Это может быть любой из атрибутов Intent, рассматриваемых Intent.filterEquals, или различные целые числа кода запроса, предоставленные для getActivity (Context, int, Intent, int), getActivities (Context, int, Intent [], int), getBroadcast (Context, int, Intent, int) или getService (Context, int, Intent, int).

7 голосов
/ 10 августа 2011

Fwiw, мне повезло больше с PendingIntent.FLAG_CANCEL_CURRENT, чем с PendingIntent.FLAG_UPDATE_CURRENT.

4 голосов
/ 18 октября 2015

У меня была такая же проблема, и я исправил ее, выполнив следующие шаги

1) Снимите флажок для намерения

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);

2) вставить intent.setAction по приведенному ниже коду

 intent.setAction(Long.toString(System.currentTimeMillis()));

3) для Pendingintent, введите следующий код

   PendingIntent Pintent = PendingIntent.getActivity(ctx,0, intent,PendingIntent.FLAG_UPDATE_CURRENT);

Я надеюсь работать с вами

1 голос
/ 31 марта 2016
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

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

0 голосов
/ 22 июня 2017

У меня та же проблема, и для ее устранения используйте PendingIntent.html.FLAG_UPDATE_CURRENT .

Я проверил исходный код. В ActivityManagerService.java ключевой метод выглядит следующим образом. Когда флаг PendingIntent.FLAG_UPDATE_CURRENT и updateCurrent имеет значение true. Некоторые дополнения будут заменены новыми, и мы получим замененный PendingIntent.

    IIntentSender getIntentSenderLocked(int type, String packageName,
            int callingUid, int userId, IBinder token, String resultWho,
            int requestCode, Intent[] intents, String[] resolvedTypes, int flags,
            Bundle bOptions) {

// ... omitted

        final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
        final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
        final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
        flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
                |PendingIntent.FLAG_UPDATE_CURRENT);

        PendingIntentRecord.Key key = new PendingIntentRecord.Key(
                type, packageName, activity, resultWho,
                requestCode, intents, resolvedTypes, flags, bOptions, userId);
        WeakReference<PendingIntentRecord> ref;
        ref = mIntentSenderRecords.get(key);
        PendingIntentRecord rec = ref != null ? ref.get() : null;
        if (rec != null) {
            if (!cancelCurrent) {
                if (updateCurrent) {
                    if (rec.key.requestIntent != null) {
                        rec.key.requestIntent.replaceExtras(intents != null ?
                                intents[intents.length - 1] : null);
                    }
                    if (intents != null) {
                        intents[intents.length-1] = rec.key.requestIntent;
                        rec.key.allIntents = intents;
                        rec.key.allResolvedTypes = resolvedTypes;
                    } else {
                        rec.key.allIntents = null;
                        rec.key.allResolvedTypes = null;
                    }
                }
                return rec;
            }
            rec.canceled = true;
            mIntentSenderRecords.remove(key);
        }
...