PendingIntent无法发送Intent附加信息

147

我的MainActivity使用带有名为isNextWeekboolean额外参数的Intent启动RefreshService

RefreshService创建一个Notification,当用户单击它时会启动我的MainActivity

效果如下:

    Log.d("Refresh", "RefreshService got: isNextWeek: " + String.valueOf(isNextWeek));

    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.putExtra(MainActivity.IS_NEXT_WEEK, isNextWeek);

    Log.d("Refresh", "RefreshService put in Intent: isNextWeek: " + String.valueOf(notificationIntent.getBooleanExtra(MainActivity.IS_NEXT_WEEK,false)));
    pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);

    builder = new NotificationCompat.Builder(this).setContentTitle("Title").setContentText("ContentText").setSmallIcon(R.drawable.ic_notification).setContentIntent(pendingIntent);
    notification = builder.build();
    // Hide the notification after its selected
    notification.flags |= Notification.FLAG_AUTO_CANCEL;
    notificationManager.notify(NOTIFICATION_REFRESH, notification);

如您所见,notificationIntent应该带有布尔值额外信息IS_NEXT_WEEK,其值为被放置在PendingIntent中的isNextWeek

当我现在点击此Notification时,isNextWeek的值总是false

这是我在MainActivity中获取该值的方式:

    isNextWeek = getIntent().getBooleanExtra(IS_NEXT_WEEK, false);

记录:

08-04 00:19:32.500  13367-13367/de.MayerhoferSimon.Vertretungsplan D/Refresh: MainActivity sent: isNextWeek: true
08-04 00:19:32.510  13367-13573/de.MayerhoferSimon.Vertretungsplan D/Refresh: RefreshService got: isNextWeek: true
08-04 00:19:32.510  13367-13573/de.MayerhoferSimon.Vertretungsplan D/Refresh: RefreshService put in Intent: isNextWeek: true
08-04 00:19:41.990  13367-13367/de.MayerhoferSimon.Vertretungsplan D/Refresh: MainActivity.onCreate got: isNextWeek: false

当我使用意图(Intent)并且设置了`isNextValue`属性,直接启动MainActivity时:

    Intent i = new Intent(this, MainActivity.class);
    i.putExtra(IS_NEXT_WEEK, isNextWeek);
    finish();
    startActivity(i);

一切都正常工作,当isNextWeektrue时,我得到true

我错在哪里,导致总是出现false的值?

更新

这解决了问题: https://dev59.com/DmMl5IYBdhLWcg3w3aTj#18049676

引用:

我怀疑,由于Intent中唯一更改的是extra,PendingIntent.getActivity(...)工厂方法仅仅是为了优化而重新使用旧Intent。

在RefreshService中尝试:

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);

参见:

http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_CANCEL_CURRENT

更新2

请查看下面的答案,解释为什么最好使用PendingIntent.FLAG_UPDATE_CURRENT


3
PendingIntent.FLAG_CANCEL_CURRENT 对我很有效,谢谢。 - Pelanes
你有问题和解决方案,太好了。我认为你应该将其作为答案添加到问题中。+10秒比+5秒更好 ;) - Muhammed Refaat
参考此解决方案:https://dev59.com/_nM_5IYBdhLWcg3w2XHw#47156455 - Muhammad Noman
FLAG_UPDATE_CURRENT在我的情况下不够用,因为同一个PendingIntent被我的小部件重复使用。最终我使用了FLAG_ONE_SHOT来处理很少发生的操作,并保留了小部件PendingIntent的完整性。 - Eir
4个回答

45

使用 PendingIntent.FLAG_CANCEL_CURRENT 并不是一个好的解决方案,因为会浪费内存。相反,应该使用 PendingIntent.FLAG_UPDATE_CURRENT

还要使用 Intent.FLAG_ACTIVITY_SINGLE_TOP (如果活动已经在历史栈的顶部运行,则不会启动该活动)。

Intent resultIntent = new Intent(this, FragmentPagerSupportActivity.class).
                    addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);  
resultIntent.putExtra(FragmentPagerSupportActivity.PAGE_NUMBER_KEY, pageNumber);

PendingIntent resultPendingIntent =
                PendingIntent.getActivity(
                        this,
                        0,
                        resultIntent,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );

那么:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        try {
            super.onCreate(savedInstanceState);

            int startPageNumber;
            if ( savedInstanceState != null)
            {
                startPageNumber = savedInstanceState.getInt(PAGE_NUMBER_KEY);
//so on

现在应该可以正常工作了。


如果你仍然遇到意外行为,请尝试实现void onNewIntent(Intent intent)事件处理程序,这样您就可以访问为活动调用的新意图(这不同于仅调用getIntent(),这将始终返回启动活动的第一个Intent。)

@Override
protected void onNewIntent(Intent intent) {
    int startPageNumber;

    if (intent != null) {
        startPageNumber = intent.getExtras().getInt(PAGE_NUMBER_KEY);
    } else {
        startPageNumber = 0;
    }
}

这也适用于 PendingIntent.getBroadcast。 - Johann

22

当你收到一个新的Intent时,我认为你需要通过在Activity中覆盖onNewIntent(Intent)来更新它。请将以下内容添加到您的Activity中:

@Override
public void onNewIntent(Intent newIntent) {
    this.setIntent(newIntent);

    // Now getIntent() returns the updated Intent
    isNextWeek = getIntent().getBooleanExtra(IS_NEXT_WEEK, false);        
}

编辑:

仅当您的Activity已在接收Intent时启动时才需要此操作。如果您的Activity是通过Intent启动(而不仅是恢复),则问题可能出在其他地方,我的建议可能无法解决它。


这也会出现在活动关闭并通过通知重新打开后。 - maysi

3
以下代码应该能够正常工作:-
int icon = R.drawable.icon;
String message = "hello";
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);

Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.putExtra("isNexWeek", true);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, pIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);

在MainActivity的onCreate方法中:

if (getIntent().getExtras() != null && getIntent().getExtras().containsKey("isNextWeek")) {
        boolean isNextWeek = getIntent().getExtras().getBoolean("isNextWeek");
}

new Notification(icon, message, when); 已被弃用。 - maysi
有没有不使用CLEAR_TOP的方法来实现它? - richardaum

0

实际原因是,如果意图只在它们的额外信息上有所不同,PendingIntent 将缓存先前的意图。在我的情况下,无论使用 PendingIntent.FLAG_UPDATE_CURRENT 还是 PendingIntent.FLAG_CANCEL_CURRENT,都无法解决这个问题,因为旧意图将被替换或新意图将保持与初始意图相同。

您需要确保 Android 不能缓存 PendingIntent 后面的 Intents。对我来说,解决方案是使它们在其数据属性上有所不同。

因此,在原始帖子的代码中,您需要确保数据属性对于您附加的每个额外信息组合都是唯一的。

    Intent notificationIntent = new Intent(this, MainActivity.class);
    notificationIntent.putExtra(MainActivity.IS_NEXT_WEEK, isNextWeek);
    notificationIntent.setData(Uri.parse("myapp://nextWeek/" + (isNextWeek ? "1" : "0"))

或者你也可以简单地在数据URI中添加一个UUID(然而,如果你有很多通知的话,缓存它们可能会更好)。

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