PendingIntent对于第一个通知正确运行,而对于其余通知则不正确


87
  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,即在运行中多次调用。UploadManageractivitydisplayNotification()AsyncTask

编辑1:我忘了提及我将String响应传递Intent intentextra

  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。但是,我目前不确定如何解决它。

Answers:


125

不要使用Intent.FLAG_ACTIVITY_NEW_TASK用于PendingIntent.getActivity,使用FLAG_ONE_SHOT代替


从评论中复制:

然后在Intent上设置一些虚拟操作,否则多余的内容将被丢弃。例如

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

我认为,由于相同的原因,此标志实际上也无法工作,我认为我的附加设备无法正常工作(请检查“编辑1”)。

32
然后在Intent上设置一些虚拟操作,否则多余的内容将被丢弃。例如intent.setAction(“ foo”)
2010年

20
优秀。那行得通。我结合使用mbauer建议的FLAG_UPDATE_CURRENT,将setAction(Long.toString(System.currentTimeMillis()))结合使用。使用FLAG_ONE_SHOT仅允许我单击一次通知(这很有意义)。非常感谢。

5
“然后在Intent上设置一些虚拟操作,否则将删除多余的内容”-是否记录在某处?
Mr_and_Mrs_D

setAction机制为我工作。据记载,不确定,但是Android的源代码可在android.googlesource.com上找到;-)
Norman H

62

在Widget上苦苦挣扎,每个都有RemoteViews不同。添加以下内容时有效:IntentsButtonHomeScreen

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

+1非常感谢。知道为什么添加intent.setAction()使其起作用吗?
AjOnFire

setAction可以工作,但是如果我实际上必须将Intent Action设置为其他东西怎么办?为什么框架如此多虫?
b.lit 2014年

2
我只是喜欢Android SDK对开发人员如此直观...(:♥️BTW阅读下面的@ObjectiveTruth答案来解释其原因setAction
Aviel Gross 2014年

1
正在出现奇怪的行为,如果没有setAction方法调用,则意向附加将在调试时起作用,但是当不调试时,意向附加将始终与第一次调用中传递的初始附加相同。我发现在调试时,总是从应用程序中导航时调用onCreate,而在不调试时,仅调用onStart而不调用onCreate。调用setAction方法解决了该问题,我猜想这是与仅在Extras值已更改的情况下意图不“不同”有关的。
MaxJ

@clu因为我已经在使用setAction,所以您可以做的是addCategoryPendingIntent用于Intent.filterEquals检查动作,数据,类型,类和类别是否相等。 developer.android.com/reference/android/content/...
iamreptar

43

采取行动为我解决了这个问题。这是我对情况的理解:


我有多个附加了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);

更新


更好的解决方案,以防您正在使用广播。唯一的PendingIntent也由唯一的请求代码定义。这是我的解决方案:

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

1
尼斯清洁解决方案
Varun Garg,2016年

1
对我来说,具有唯一ID和PendingIntent.FLAG_ONE_SHOT的待定意图,以及对意图的setAction均有效。
Kaustuv '16

它不考虑意图变更的额外变更有点奇怪,但似乎是真的:/
zeroDivider

20

我看到了答案,但没有任何解释。同样,所有答案都无法解决所有可能的解决方案,因此,我将尽力弄清楚。

说明文件:

如果您确实确实需要同时激活多个不同的PendingIntent对象(例如用作同时显示的两个通知),那么您需要确保它们之间存在一些不同之处,以便将它们与不同的对象关联待定意向。这可以是Intent.filterEquals考虑的任何Intent属性,也可以是提供给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);

但是,这两个意图是相等的,因此,当您的第二个通知到达时,它将启动第一个意图。

解:

您必须使每个意图都是唯一的,以便没有待决的意图永远相等。您如何使意图独特?并非凭您所付出的额外费用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值,这意味着某些数字将被删除。因此,我建议选择类别操作并设置唯一的字符串。


这最终对我有用,它为每个通知使用唯一的ID(无论如何都需要取消),并为每个操作使用自定义类别(在同一通知中永远不会有多个相同类型的操作)。
MandisaW

是的,我也为每种意图都使用了一个唯一的类别,它的效果很好。
steliosf

有同样的问题。同时触发两个通知。当我单击第二个通知时,没有任何反应。设置此setAction(Long.toString(System.currentTimeMillis()))之后;。它的运作就像魅力。感谢您的出色解释@MScott
Anantha Babu

13

我遇到了同样的问题,并且可以通过将标志更改为来解决此问题:

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

非常感谢您抽出宝贵的时间为您解决问题。我忘了提及我在Intent中传递了更多内容。这使问题更加复杂。检查我的编辑1.

9

正如文档所述,使用唯一的请求代码:

如果您确实确实需要同时激活多个不同的PendingIntent对象(例如用作同时显示的两个通知),那么您需要确保它们之间存在一些不同之处,以便将它们与不同的对象关联待定意向。这可以是Intent.filterEquals考虑的任何Intent属性,也可以是提供给getActivity(Context,int,Intent,int),getActivities(Context,int,Intent [],int),getBroadcast(Context,int)的不同请求代码整数。 ,Intent,int或getService(Context,int,Intent,int)。


1
这是唯一的正确答案。正在寻找它,因为我想发布相同的内容。:-)
Sevastyan Savanyuk

7

Fwiw,我拥有的运气PendingIntent.FLAG_CANCEL_CURRENT比拥有的要好PendingIntent.FLAG_UPDATE_CURRENT


我完全同意这种说法。如果我们可以使意图取消旧的,然后再创建新的,则无需用无用的额外内容填充意图。的确,有时什么也没做,可能没有用,但是现在的问题是“节省内存或节省时间”。
zeroDivider

4

我有同样的问题,我通过以下步骤解决了

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
任何人都想解释为什么这个答案被否决了。这对我有用。我不知道这是否是合法的答案,但是此解决方案是完美的解决方案。至少对于我来说。
Sandeep R

也为我工作!谢谢!
安德烈斯(Andres)

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

在PendingIntent中有两个int参数,第二个和最后一个。第二个是“请求代码”,它必须是唯一编号(例如,通知的ID),否则为(例如,在您的示例中为零,则它将始终被覆盖)。


0
// 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());

0

发送额外的数据正确,您应该挂起意图发送通知ID是这样的:的PendingIntent的PendingIntent = PendingIntent.getActivity(背景下,(INT)System.currentTimeMillis的() ,意向,PendingIntent.FLAG_UPDATE_CURRENT);


0

我有同样的问题,请使用PendingIntent.html.FLAG_UPDATE_CURRENT进行修复。

我已经检查了源代码。在ActivityManagerService.java中,关键方法如下。当标志为PendingIntent.FLAG_UPDATE_CURRENT且updateCurrent为true时。一些附加功能将被new替换,我们将获得一个替换的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);
        }


-5

我遇到了同样的问题,并且可以通过将标志更改为来解决此问题:

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

    }

4
它与提出的问题无关。
Paul Turchenko 2013年

需要澄清它与这个问题的关系。
Norman H
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.