通知传递旧的意图扩展信息

149

我正在通过以下代码在BroadcastReceiver中创建一个通知:

String ns = Context.NOTIFICATION_SERVICE;
        NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(ns);
        int icon = R.drawable.ic_stat_notification;
        CharSequence tickerText = "New Notification";
        long when = System.currentTimeMillis();

        Notification notification = new Notification(icon, tickerText, when);
        notification.defaults |= Notification.DEFAULT_VIBRATE;
        long[] vibrate = {0,100,200,200,200,200};
        notification.vibrate = vibrate;
        notification.flags |= Notification.FLAG_AUTO_CANCEL;

        CharSequence contentTitle = "Title";
        CharSequence contentText = "Text";
        Intent notificationIntent = new Intent(context, NotificationActivity.class);
        notificationIntent.putExtra(Global.INTENT_EXTRA_FOO_ID, foo_id);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

        notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);

        int mynotification_id = 1;

        mNotificationManager.notify(mynotification_id, notification);
当我点击通知时,它会打开NotificationActivity,在Activity中我可以从Intent-Bundle(例如1)中检索foo_id。但是,如果触发另一个通知并再次单击它,则该活动仍会从Intent-Bundle接收“旧”值(1)。 我已尝试使用clear()清除捆绑包,但仍然出现相同的效果。我认为我的代码有问题……

请问您如何从PendingIntent中获取数据? - user49557
意识到它正在发送旧的额外信息,使我的故障排除变得更容易了。 - Utsav Gupta
7个回答

290

你正在为你的待处理意图发送相同的请求代码。 请改为:

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

收件人:

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

如果您发送相同的参数,则不会创建意向,它们将被重复使用。


1
那么UNIQUE_INT_PER_CALL是我需要提供的整数吗?还是这是在某处声明的静态变量? - BrianM
26
Android Gotcha #147指出,如果我在调用PendingIntent时没有提供唯一的ID,那么具有不同额外信息(通过putExtra)的“意图”将被视为相同并被重复使用。这是一个糟糕的API设计。需要注意的是,翻译内容不能改变原意,也不能包含解释或其他信息。 - wal
你知道吗,我太粗心了。只是在想怎么可能会在一个块中保持为0(在我的情况下):( - Exigente05
3
这对我非常有用,给其他人的一个提示是,你很可能正在使用相同的方法构建通知,因此你可以将新的待定意图的ID设置为与你将用于通知唯一ID相同的值! - James McNee
2
@IncrediApp,它和PendingIntent.getBroadcast()一样吗? - Shruti

146

或者,您可以使用以下代码生成您的PendingIntent:

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

根据PendingIntent.FLAG_UPDATE_CURRENT的文档:

如果所描述的PendingIntent已经存在,则保留它,但将其额外数据替换为此新意图中的数据。 如果您创建的意图仅extras更改,并且不关心任何实体是否能够使用您的新extra启动先前接收到的PendingIntent,即使它们没有明确地给出给它,那么可以使用此选项。


谢谢...对于需要添加"PendingIntent.FLAG_UPDATE_CURRENT"标志的操作,这个代码完美地运行了 :) - Najib.Nj
1
使用挂起意图将状态从设置闹钟传递到广播接收器,对我很有效。 - William T. Mallard
我真希望在向我的用户发送通知之前就知道这些标志的实际作用!很高兴这解决了我的烦恼... - James Andrew

46

你正在传递相同的ID。在这种情况下,可以通过当前时间创建一个唯一的ID,方法如下:

int iUniqueId = (int) (System.currentTimeMillis() & 0xfffffff);

将它放在这里:

PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),iUniqueId, intentForNotification, 0);

4
为什么不使用new Random().nextInt()?为什么不使用new Random().nextInt()? - exloong
@hderanga 在上面的 int 中添加“&0xfffffff”是做什么用的? - AJW
4
System.currentTimeMillis() 返回一个长整型,而 PendingIntent.getActivity() 方法中的 requestId 参数接收一个整型。0xffffffff 是一个掩码。简单来说,通过执行 long & 0xffffffff' 操作可以得到长整型的最低32位,并丢弃最高32位,从而获得一个32位的整型。这比直接将长整型强制转换为整型要好,因为这样不会对符号位造成影响(如果强制转换一个大于整型最大值的长整型为整型,则符号位将溢出并可能得到一个负值)。 - Jordan

10

如果您长时间之后寻找最佳方法,您需要像下面所示将PendingIntent.FLAG_UPDATE_CURRENT作为最后一个参数传递。

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

您甚至不需要提供一个新的唯一标识符。

这是下一次及以后需要做的,而非第一次。


2
那不起作用,我到这里来就是因为那是我正在做的事情。 - Brill Pappin
下一次你需要这样做,而不是第一次,它会起作用。 - Gentle

0

您的所有通知请求代码均为0。请更改以下行:

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

使用:

PendingIntent contentIntent = PendingIntent.getActivity(context, new Random().nextInt(), notificationIntent, 0);

1
使用“new Random().nextInt()”而不是“System.currentTimeMillis()”有什么好处吗? - AJW
使用随机数可能会意外地再次生成相同的整数值,从而导致传递旧意图的非常难以发现的错误。 - Sam
@AJW 在我的情况下是这样的。我在完全相同的毫秒内创建了2个不同的通知,因此其中一个通知得到了错误的额外信息。 - artman

0

我只是想再添加另一个选项

 PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);

0

试一下,它适用于安卓12及以上版本

PendingIntent pendingIntent;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
            pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT );
        } else {
            pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接