8

我有一个使用Urban Airship进行推送通知的应用程序。当通知到达并且用户单击它时,我的应用程序中的活动 A 应该打开并执行某些操作。

我已经安装了文档BroadcastReceiver中显示的内容,并且几乎可以正常工作。

  1. 当我的应用程序在前台时,我根本不会让用户看到通知,而是自动处理它。
  2. 当我的应用程序根本没有运行时,活动打开就好了。
  3. 当我的应用程序在后台时(当 A 是顶级活动时总是发生这种情况),将创建 Activity A 的第二个实例

这当然是个问题。我不想要两个 A 活动,我只想要其中一个。以下是相关BroadcastReceiver代码:

@Override
public void onReceive(Context ctx, Intent intent)
{
    Log.i(tag, "Push notification received: " + intent.toString());
    String action = intent.getAction();
    int notificationId = intent.getIntExtra(PushManager.EXTRA_NOTIFICATION_ID, -1);
    if(action.equals(PushManager.ACTION_NOTIFICATION_OPENED))
    {
        Intent intentActivity = new Intent(ctx, ActivityA.class);
        intentActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        UAirship.shared().getApplicationContext().startActivity((intentActivity);
    }
}

更新:当用户在活动 A 上按返回时,我试图通过调用来绕过此错误System.exit(0)。该过程结束,但随后立即重新启动!在第二种情况下,我的 BroadcastReceiver 不再被调用。发生了什么?

更新 2:@codeMagic 询问有关应用程序和活动 A 的更多信息。

此应用程序允许其用户查看某些项目并对其发表评论。Activity A 在应用程序启动时启动。如果用户的会话不再有效,则启动登录活动。用户登录后,活动 A 再次变为活动状态。A 只有“没有要查看的项目”消息和“立即尝试”按钮。

当用户登录时,只要有新项目可供查看,服务器就会开始发送推送通知。当应用程序收到通知时,活动 A 访问服务器并获取下一个要查看的项目。该项目显示在活动 B 中。将评论提交到服务器后,活动 B 完成,活动 A 再次成为最重要的活动。

服务器知道用户何时正在审查一个项目(因为活动 A 获取了它),并且在提交审查之前不会发送推送通知 - 这意味着如果用户未登录或如果用户未发送通知正在查看活动 B。

虽然我同意这里有一个微妙的竞争条件,但它并没有导致我看到的问题 - 在测试中我 100% 肯定没有竞争条件 - 推送通知仅在活动 A 再次激活后发送。

4

4 回答 4

24

解决方案是launchMode='singleTask'AndroidManifest.xml. 结果,onNewIntent调用了相同活动实例的而不是新活动。

于 2013-05-02T07:10:55.270 回答
2

您可以使用几个Intent Flags. FLAG_ACTIVITY_REORDER_TO_FRONT就是其中之一。如果它已经在堆栈中,这将把它带到Activity堆栈的前面,如果没有,那么它将创建一个新实例。我相信FLAG_ACTIVITY_NEW_TASK如果您不从Activity

Intent.FLAG_ACTIVITY_CLEAR_TOP也应该工作。但这将清除Activities堆栈上的任何其他内容。这仅取决于您需要的其他功能。查看Intent Flags,看看哪些最适合您

于 2013-05-01T22:07:33.370 回答
0

有多种情况可能发生这种情况。其中一个可以这样处理。请在此处查看我的答案:https ://stackoverflow.com/a/44117025/2959575

于 2017-05-22T15:45:00.753 回答
-2

好的,对此有两个注意事项:

  • 您可以通过清单注册广播接收器,使其独立于应用程序的任何部分。并使用单例模式(在您的应用程序中的某处保留对您的活动的静态引用),这样您就可以检查它们是否是活动查看并相应地进行处理。

    // your activity A
    
    @Override
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        myActivityReference = this;
    }
    
    public void onPause() {
        super.onPause();
        if (isFinishing()) {
            myActivityReference = null;
        }
    }
    
  • 或者您可以保持一切原样并在清单中使用活动午餐模式标志,例如singleTop, singleInstance ... etc. 看看这里android 活动午餐模式

于 2013-05-01T22:09:01.147 回答