Android会缓存我的意图附加项,如何声明一个保持新鲜的附加项的挂起意图?

64

几天前,我苦苦寻找一种使用自定义意图来设置闹钟的方法。尽管我得到了明确的答案,即我必须基于某个唯一的ID定制意图,例如setAction(),但仍然存在一些问题。

我这样定义了一个PendingIntent:

Intent intent = new Intent(this, viewContactQuick.class);
intent.setAction("newmessage"+objContact.getId());//unique per contact
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK ).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP );
intent.putExtra("id", Long.parseLong(objContact.getId()));
intent.putExtra("results", result.toArray());

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

那么这会被通知管理器使用。

NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(ns);
// first try to clear any active notification with this contact ID
mNotificationManager.cancel(Integer.parseInt(objContact.getId()));

// then raise a new notification for this contact ID
mNotificationManager.notify(Integer.parseInt(objContact.getId()), notification);

这是实现方式:

  • 应用程序为联系人创建一条消息
  • 提供一个带有联系人 ID 和消息详细信息的Intent
  • 使用该消息触发通知
  • 用户在通知上执行操作,应用程序会显示意图传递的消息

问题

同一个联系人可能会收到多条消息。当第二条消息生成时,通知也能正常弹出(消息正常),但是当用户操作通知时,该intent使用旧数据而不是新数据传递,即传递的是之前的消息而非全新的消息。

所以用某种方法使得intent对于每个联系人和每个动作都是唯一的吗?


有没有一种方法可以清除所有缓存的IntentExtras?我认为现在已经修复了,但是旧的缓存意图仍然存在... - OneWorld
根据Intent的标志或活动的launchMode,可能会出现类似的问题。在这种情况下,您需要检查[Activity :: onNewIntent](http://j.mp/ieXMCA),因为Activity :: getIntent将返回Activity的原始意图,而不是具有更新操作/附加内容等的新意图。 - brack
3个回答

103

如果您针对此联系人的PendingIntents只有一个处于未完成状态,或者始终希望使用最新的extras集合,则在创建PendingIntent时请使用FLAG_UPDATE_CURRENT

如果将同时存在多个特定于联系人的PendingIntent,并且它们需要具有不同的extras,则需要添加计数、时间戳或其他内容以区分它们。

intent.setAction("actionstring" + System.currentTimeMillis());

更新

另外,轻度文档化的getActivity()PendingIntent上的类似参数显然可用于为相同的基础Intent创建不同的PendingIntent对象,尽管我从未尝试过。


1
我最终在操作中添加了一个时间戳。 - Pentium10
1
太棒了!我使用了当前的小部件ID来将它们分开(还允许一定程度的缓存)。 - DavidG
1
很棒的答案!我可以确认将getActivity()的第二个参数设置为随机整数可以解决这个问题。可惜它是一个已弃用的参数? - IgorGanapolsky
4
@IgorG.: 那个参数并没有被弃用。文档声称它没有被使用,但是在这个领域显然文档存在缺陷。 - CommonsWare
我认为这就是filterEquals()和filterHashCode()存在的原因。但现在似乎它们不再起作用了:http://stackoverflow.com/questions/13553911/intent-filterequals-and-filterhashcode-are-no-longer-invoked-when-creating-pendi - AlikElzin-kilaka
显示剩余4条评论

40

我通常指定一个独特的requestCode来防止我的PendingIntents相互覆盖:

PendingIntent pending = PendingIntent.getService(context, unique_id, intent, 0);

而在你的情况下,我同意CommonsWare所说,你只需要使用FLAG_UPDATE_CURRENT标志。新的extras将会覆盖旧的值。


1
这还不足以防止您的PendingIntent相互冲突。您还必须使用PendingIntent.FLAG_UPDATE_CURRENT。 - IgorGanapolsky
生成唯一标识符的好方法是 int unique_id = (int) System.currentTimeMillis(); - Glenn Sonna
我不确定你是否可以在那里使用Long,或者实际上是任意随机的Int。如果我没记错的话,如果您在请求代码中使用“较大”字节中的任何位,Android将抛出异常,这基本上限制了您只能使用小的正数。 - milosmns
找到了,类似这样的 - https://dev59.com/u1wX5IYBdhLWcg3w0iUc - milosmns

0
找到了一个简单的解决方案,关键是请求代码。
int requestCode = (int) System.currentTimeMillis();

PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_IMMUTABLE);

如果您对每个PendingIntent使用相同的请求代码,Android将视其为相同的请求,返回您在第一个请求中放置的相同的Extras。

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