PendingIntent работает правильно для первого уведомления, но неправильно для остальных

  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: я забыл упомянуть, что передаю ответ String в 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, дополнительный "ответ" отражает то, что ответ строки был при последнем вызове displayNotification().

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

Ответ 1

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


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

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

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

Ответ 2

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

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

Ответ 3

Установить действие. Решено для меня. Вот мое понимание ситуации:


У меня есть несколько виджетов, на которые есть 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);

Ответ 4

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

PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

1) Очистить любой флаг для намерения

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

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

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

3) для Pendingintent, введите ниже код

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

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

Ответ 8

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

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

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

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

Вы создаете 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, что означает, что некоторые цифры будут удалены. Поэтому я бы рекомендовал либо перейти с категорию, либо действие и установить уникальную строку.

Ответ 9

PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);

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

Ответ 10

// Use pending Intent and  also use unique id for display notification....
// Get a PendingIntent containing the entire back stack
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationManager mNotificationManager = (NotificationManager)  sqlitewraper.context.getSystemService(Context.NOTIFICATION_SERVICE);
// Issue the notification
mNotificationManager.notify(id, builder.build());

Ответ 11

чтобы отправить данные правильно, вы должны отправить с ожидающим намерение идентификатор уведомления следующим образом: PendingIntent pendingIntent = PendingIntent.getActivity(контекст, (int) System.currentTimeMillis(), намерение, PendingIntent.FLAG_UPDATE_CURRENT);

Ответ 12

У меня такая же проблема, и используйте 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);
        }

Ответ 13

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

LayoutInflater factory = LayoutInflater.from(this);            
      final View textEntryView = factory.inflate(R.layout.appointment, null);
      AlertDialog.Builder bulider= new AlertDialog.Builder(PatientDetail.this);
      final AlertDialog alert=bulider.create();


        bulider.setTitle("Enter Date/Time");
        bulider.setView(textEntryView);
        bulider.setPositiveButton("Save", new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface dialog, int which) {
                      EditText typeText=(EditText) textEntryView.findViewById(R.id.Editdate);
                      EditText input1 =(EditText) textEntryView.findViewById(R.id.Edittime);
                      getDateAndTime(typeText.getText().toString(),input1.getText().toString());
                }
            });
        bulider.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

                public void onClick(DialogInterface dialog, int which) {
                    dialog.cancel();
                }
            });

        bulider.show();

    }