未触发 Android 通知操作 (PendingIntent)

Posted

技术标签:

【中文标题】未触发 Android 通知操作 (PendingIntent)【英文标题】:Android Notification Action is not fired (PendingIntent) 【发布时间】:2013-01-28 07:14:42 【问题描述】:

我正在尝试在我的音乐播放器应用中添加通知操作项。当流启动时,应触发通知,并且应在通知中显示流的停止按钮。到目前为止,通知工作正常,我遇到了停止操作项的问题。以下是它在启动流的服务中的声明方式:

Intent stopIntent = new Intent(this, MusicPlayerNew.class);
stopIntent.putExtra("STOP", "STOP");
PendingIntent stopPendingIntent = PendingIntent.getActivity(this, 0,
                stopIntent, PendingIntent.FLAG_UPDATE_CURRENT, null);
mBuilder.addAction(R.drawable.ic_stat_stop, "Stop", stopPendingIntent);

现在在我的活动的 onResume() 方法中,我使用 getIntent().getStringExtra() 检查“STOP”额外内容,但我通过 getIntent() 检索到的意图没有设置额外内容:(

我还尝试检查是否发送广播(我有一个广播接收器,用于从服务到活动进行通信)

Intent stopIntent2 = new Intent(MusicPlayerNew.STOP_MEDIAPLAYER);
PendingIntent stopPendingIntent2 = PendingIntent.getBroadcast(this, 0,
                stopIntent2, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.addAction(R.drawable.ic_stat_stop, "Stop", stopPendingIntent2); 

现在,如果活动当前处于前台,则此方法有效。如果活动在后台,停止按钮什么也不做:(

编辑: 我的 Activity 中有 BroadcastReceiver 作为私有类

private class DataUpdateReceiver extends BroadcastReceiver 
        @Override
        public void onReceive(Context context, Intent intent) 
..

在 onResume() 中为这个接收者注册我的应用程序:

intentFilter = new IntentFilter(STOP_MEDIAPLAYER);
registerReceiver(dataUpdateReceiver, intentFilter);

onPause()

unregisterReceiver(dataUpdateReceiver);

现在,如果我从 onPause() 方法中删除取消注册,即使应用程序/活动不再处于前台,也会收到广播。但这是正确的方法吗?我认为我从网上的教程中得到了这个注册/取消注册的东西..

【问题讨论】:

我在 KitKat 上有同样的问题。我有两个动作,第一个叫罚款,第二个根本不叫。你找到解决这个问题的方法了吗? 好的,我找到了解决方案。看看我的答案底部。 【参考方案1】:

这是一个很晚的答案,但它可能对某人有所帮助:

您应该根据要运行的意图选择正确的待处理意图。以下是一些示例:

对于活动,请使用以下:

Intent i = new Intent(this, YourActivity.class);
PendingIntent pi = PendingIntent.getActivity(this, 0, i, 0);

对于服务,请使用以下:

Intent i = new Intent(this, YourService.class);
PendingIntent pi = PendingIntent.getService(this, 0, i, 0);

对于广播接收器,请使用以下:

Intent i = new Intent(this, YourReciver.class);
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);

如果需要,您可能需要更改请求代码和标志

【讨论】:

我将意图发送到服务,但随后重构为 BroadcastReceiver。 它可能对某人有所帮助。它帮助我意识到我正在使用 getService,但需要更改为 getActivity.. 谢谢!【参考方案2】:

我在谷歌代码https://code.google.com/p/android/issues/detail?id=61850的这个帖子中找到了解决方案

要修复它,您必须将 PendingIntent.FLAG_CANCEL_CURRENT 标志添加到您的 PendingIntent

PendingIntent stopPendingIntent2 = PendingIntent.getBroadcast(this, 0,
            stopIntent2, PendingIntent.FLAG_CANCEL_CURRENT);

【讨论】:

谢谢。当我遇到类似的问题时,这真的让我发疯了。这成功了。可能重新启动设备也会有所帮助,但这很干净。【参考方案3】:

我今天遇到了这个问题。在我的情况下,它使用了来自先前意图实例的缓存意图附加内容,因为 pendingIntent 构造函数的所有参数都是相同的。我为此找到了两种解决方案...

    使用 Nik 提到的 FLAG_CANCEL_CURRENT。

    将唯一的requestCode 传递给pendingIntent,如下所示

    PendingIntent pi = PendingIntent.getService(this, UNIQUE_ID, pi, 0);
    

就我而言,第二种方法解决了这个问题,因为我需要保持之前的通知有效。可能这会对有类似问题的人有所帮助。

【讨论】:

我认为不需要 UNIQUE_ID,除非与其他服务发生冲突。【参考方案4】:

我今天遇到了这个问题,它是由于没有注册或添加到 AndroidManifest.xml 的活动引起的。我以为我有它,但它不是。此外,尝试使用其意图调用该操作时没有记录任何错误。

我通过创建一个意图然后在不使用通知的情况下调用 startAcitivty(intent) 来解决这个问题。然后它给了我一个错误,说明清单中可能缺少该活动。

如果其他答案都不能解决您的问题,那么希望这能解决。通常棘手的问题是一些简单而愚蠢的事情的结果。

【讨论】:

【参考方案5】:

除了使用广播接收器之外,您还应该使用服务并以这种方式在服务中声明新操作:

public final String ACTION_STOP = "yourpackagename.ACTION_STOP";

然后像这样创建你的意图:

Intent stopIntent = new Intent(this, YourService.class).setAction(YourService.ACTION_STOP);
PendingIntent stopPendingIntent = PendingIntent.getService(this, 0, stopIntent, 0);

当然,如果 Intent 的操作等于 ACTION_STOP,则在服务的函数 startCommand 中停止播放。

这应该可以解决问题;)

【讨论】:

【参考方案6】:

不要使用显式 Intent

在我的例子中,我在 Service 类中创建了一个动态上下文注册的 BroadcastReceiver 来监听通知操作。


class MyService:Service()

private val receiver: BroadcastReceiver = NotificationActionReceiver()
...

inner class NotificationActionReceiver : BroadcastReceiver() 
        override fun onReceive(context: Context, intent: Intent) 
            ...
        
 

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int 
        ...
        registerReceiver(receiver,IntentFilter("SOME_ACTION"))
        return super.onStartCommand(intent, flags, startId)
 

override fun onDestroy() 
        ...
        unregisterReceiver(receiver)
        super.onDestroy()
 

PendingIntent 带有显式 Intent


val nextIntent = Intent(this, NotificationActionReceiver::class.java) //Explicit Intent
val nextPendingIntent: PendingIntent= PendingIntent.getBroadcast(this,0x11,nextIntent, PendingIntent.FLAG_CANCEL_CURRENT)

但是,使用此设置,BroadcastReceiver 从未触发。

为了让它发挥作用,我需要用隐含的意图替换我的显式意图

所以我所做的只是,


val nextIntent = Intent("SOME_ACTION") //Implicit Intent
val nextPendingIntent: PendingIntent= PendingIntent.getBroadcast(this,0x11,nextIntent, PendingIntent.FLAG_CANCEL_CURRENT)

注意:由于 BroadcastReceiver 是动态注册的上下文,您不必担心隐式意图的限制

【讨论】:

谢谢老兄,浪费时间来解决这个问题【参考方案7】:

您在后台收不到广播,因为您正在取消注册 onPause。将 unregisterReceiver 代码移至 onDestroy 函数。这只会在活动被销毁时调用。或者,您可以在预期事件发生后取消注册。

【讨论】:

【参考方案8】:

这里有多个问题:

第 1 部分:为什么您的意图没有收到额外的“STOP”? 虽然在您提供的代码中没有看到,但我想确认您是否使用标志 FLAG_ACTIVITY_SINGLE_TOP 来表示通知意图?如果是这样,您在活动中收到的意图将是启动活动的意图,因此“停止”额外内容将不可用。在这种情况下,您需要扩展onNewIntent()(发送新意图的位置)。 More info here. 如果你没有使用过 FLAG_ACTIVITY_SINGLE_TOP,那么这意味着在点击通知时会创建一个新的活动,在这种情况下,Intent 必须具有“STOP”参数。如果您能提供所有相关代码,我可以更好地帮助您。

第 2 部分:使用广播接收器 正如您已经发现的那样,这不是直截了当的。您需要在 onDestroy 中注销,如果您的活动被用户关闭,则 onDestroy 可能会被调用,并且您的广播接收器可能在用户点击通知时未激活。如果您根本不取消注册,它似乎可以正常工作,但这是内存泄漏,GC 可能随时清理,这可能导致您的程序崩溃,即,您必须取消注册。如果您需要使用广播接收器方法,则需要有一个服务来执行此操作,并且服务有其自身的缺陷 -> 由系统重启、电池耗尽等。我强烈建议您使用第一种方法。

【讨论】:

【参考方案9】:

我遇到了一个非常相似的问题,但解决方案却截然不同。如果您在 manifest.xml 文件中声明了<service android:enabled="false"></service>,则也不会触发待处理的意图。

android:enabled="false"替换为android:enabled="true"

这可能不是问题的直接问题。但是,如果您在 android studio 中使用默认模板创建服务,它会自动将这些属性添加到服务中。

【讨论】:

【参考方案10】:

对我来说,解决方案是设置意图标志:

resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                Intent.FLAG_ACTIVITY_CLEAR_TASK);

【讨论】:

以上是关于未触发 Android 通知操作 (PendingIntent)的主要内容,如果未能解决你的问题,请参考以下文章

当应用程序处于打盹模式时,警报管理器触发的 Android 通知未触发

ServiceNow 推送通知卡在“待处理”中

UNUserNotificationCenter Swift - 在特定情况下未触发本地通知

Android pushwoosh:从通知(带触发器)启动应用程序时,如何避免显示“使用完成操作”对话框

PushSharp 事件未针对 WP8 触发

收到推送通知后如何触发操作[关闭]