如何在创建后通过更改活动来处理推送通知意图?

Posted

技术标签:

【中文标题】如何在创建后通过更改活动来处理推送通知意图?【英文标题】:How can I handle a push notification intent with changing activities after creation? 【发布时间】:2020-10-29 10:27:21 【问题描述】:

我有一个两个活动的 android 应用程序(活动都是单顶的),我正在处理推送通知。每个推送通知场景对我来说都得到了完美的处理,除了一个,这是因为推送通知意图的构造方式。

没有按预期执行的情况是,当推送通知进入时用户处于一个活动中,然后他们导航到另一个活动,此时他们决定从手机的下拉列表中选择推送通知酒吧。我的问题是该应用程序随后会尝试返回创建通知时处于活动状态的活动,这不是我想要的。我希望它仍然以相同的方式对通知及其数据执行所有操作,而是在当前活动上执行此操作,而不是切换回来。

我知道为什么会这样,因为通知创建代码是这样设计的:

// create notification
        val builder = NotificationCompat.Builder(context,
                channelId)
// more things are done to set up the builder...


// here is why the problem is happening

        val notificationIntent = if (we_are_in_activity_one)
                Intent(context, ActivityOne::class.java) 
            else
                Intent(context, ActivityTwo::class.java)

        notificationIntent.putExtras(data_from_notification)

        builder.setContentIntent(PendingIntent.getActivity(context,
                notificationId,
                notificationIntent,
                PendingIntent.FLAG_UPDATE_CURRENT))
        //Auto cancel
        builder.setAutoCancel(true)

        builder.priority = NotificationCompat.PRIORITY_HIGH

        //Return the generated notification
        return builder

我想知道的是可以做什么或改变什么,以便当用户选择通知时,如果情况发生变化,它不会自动启动它最初捆绑的活动。有没有我可以使用的明显标志?

另一条可能有用的信息是,只有在活动 2 中才会出现问题,因为活动 1 是启动器活动。因此,如果通知是在 2 中创建的,但它们导航回 1,则 Activity 2 将不再处于活动状态。当他们点击通知时,它会重新启动活动 2,这不是我想要的。如果通知仍然处于活动状态(也就是用户仍然在上面),我只希望通知实际上返回到活动 2。

提前致谢,如果我能提供更多有用的信息,请告诉我

【问题讨论】:

【参考方案1】:

如果我理解正确,您想收到有关用户当前活动的通知吗?

你可以这样做。

您需要验证第二个活动是否正在运行。如果不是,您的通知将在主屏幕上打开。如果是,则通知将在onNewIntent() 中打开。

实现这一目标的简单方法是:

  public static boolean isActivityActive(Activity activity) 
   return !activity.isFinishing() && !activity.isDestroyed();
  

然后

  Intent intent = new Intent(context, !isActivityActive(new ActivityTwo()) ? ActivityOne.class : ActivityTwo.class);

如果活动打开,此方法将返回 true。 或者,您可以使用:

  activity.getWindow().getDecorView().isShown();

isActivityActive(Activity)这个表达式返回的值在onStart()/onStop()中变化

如果上述方法没有提供您期望的结果,您可以创建一个类以供重用并将活动状态保存到您可以在任何活动中使用的共享密钥。

只需要几行代码。

首先执行以下操作:

 public class MyPreference 

   private Context c;
   private SharedPreferences.Editor editor;
   private SharedPreferences preferences;
   
   public MyPreference (Context c) 
    this.c = c;
    preferences = c.getSharedPreferences("shared_preferences", Context.MODE_PRIVATE);
   
   
   public void save (String preference, boolean value) 
    editor = preferences.edit();
    editor.putBoolean(preference, value);
    editor.apply();
   

   public boolean boo (String preference) 
    return preferences.getBoolean(preference, false);
   
   
   public String is_second_activity_active = "is_second_activity_active";
   
 

您现在可以通过启动MyPreference 来保存第二个活动的生命周期,如下所示:

 public class ActivityTwo extends AppCompatActivity 

   MyPreference p;
   
   @Override
   protected void onCreate(Bundle state) 
    super.onCreate(state);
    p = new MyPreference(context);
    // some source...
   
   
   @Override
   protected void onStart() 
    super.onStart();
    p.save(p.is_second_activity_active, true);
    // your activity is active
   
   
   @Override
   protected void onStop() 
    super.onStop();
    p.save(p.is_second_activity_active, false);
    // your activity is not active
   
 

可以了解Activityhere的生命周期

最后,在您的通知类中,检索您的第二个活动的状态:

  // create notification
  // ...    

  MyPreference p = new MyPreference(context);

  Intent intent = new Intent
   (context, p.boo(p.is_second_activity_active) ? ActivityTwo.class : ActivityOne.class);

  // continue...

对不起,我的英语不太流利。我希望你明白。 我不是用kotlin写的,所以你可以转换代码。

如果对您有帮助,请告诉我。 谢谢你。 >



改变



在以一种方式创建通知后,无法更改通知的行为。当情况发生变化时,您可以更新通知。

您需要在您的NotificationCompat.Builder 中定义setOnlyAlertOnce (true),然后使用与旧通知相同的id 发送新通知。

如果idsetOnlyAlertOnce (true) 相同,您的通知将更新,不会弹出、声音或振动警告。您可以为每次更新使用相同的 Builder。

虽然这样效果不错,但是文档本身就警告说,如果短时间内多次更新通知,有些通知是不会被打包的。

警告:Android 在更新通知时会应用速率限制。如果您过于频繁地发布通知更新(很多都在不到一秒的时间内),系统可能会丢弃一些更新。 Documentation

在您的情况下,每当用户登录和退出ActivityTwo.class 时都需要更新通知,这不是一件好事。

或者,我建议你试试这个。

不是直接通过通知打开活动,而是从BroadcastReceiver打开它, 然后决定打开哪个活动..

要广播您的通知,您的 Intent 需要如下所示

 // create notification
 // ...  
 
 Intent intent = new Intent();
 intent.setAction(MyNotification.ACTION_OPEN);
 intent.putExtra("get", "something");
 
 // use getBroadCast instead of getActivity
 PendingIntent pIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);

 builder.setContentIntent(pIntent);
 // configure your builder normally

现在在您的BroadcastReceiver 中,确保用户打开了他们的通知,以及他们在打开通知时正在进行的活动。

 public class MyNotification extends BroadcastReceiver 

    public static String ACTION_OPEN = "com.example.intent.action.NOTIFICATION_OPEN";
 
    @Override
    public void onReceive(Context context, Intent intent) 
      
      MyPreference m = new MyPreference(context);
      boolean open_notification = ACTION_OPEN.equals(intent.getAction());

      if (open_notification ) 
        boolean is_active = m.boo(m.is_second_activity_active);
        String log = is_active ? "Open in ActivityTwo" : "Open in ActivityOne";
        
        Intent new_intent = new Intent(context, is_active ? two.class : one.class);
        new_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        new_intent.putExtra("get", intent.getExtras());
        context.startActivity(new_intent);
        
        Log.e("log", log);
      
    
 

如果您愿意,可以使用您的方法来确定用户是否在第二个活动中,或者使用我之前提到的示例。

注意: onStart() 和 onStop() 方法实际上比 onResume() 和 onDestroy() 更好地检查用户是否仍在活动中。 当用户从最近的应用程序中关闭应用程序时,永远不会调用 onDestroy()。

最后,在你的AndroidManifest.xml声明你的广播

  <receiver android:name=".MyNotification"
        android:exported="false">
        <intent-filter>
            <action android:name="com.example.intent.action.NOTIFICATION_OPEN" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
  </receiver>

不要忘记将android:launchMode="singleTop" 添加到您的ActivityOneActivityTwo

通知将根据用户的活动打开,无论它是在哪里创建的。

因此,如果活动是唯一发生变化的事物,则无需在情况发生变化时更新通知。

它现在应该可以工作了。 x-x

【讨论】:

我喜欢您在此处介绍的两种方法。但是,我已经有一个系统来确定第二个活动是否处于活动状态。我的问题实际上是通知意图是自动且正确地创建的,但是如果用户直到稍后在不同的活动中才真正对其采取行动,那么应用程序会返回到通知进入时用户所在的第二个活动并被创建。我希望在打开应用程序及其活动之前修改意图的活动,或者看看是否有任何其他方法。 感谢您的帮助和详细的代码回复!我最终使用了一种采用您的方法的方法,以及对我们自定义设置的更改,其中包含 2 个活动,其中涉及在从通知中打开第二个活动并恢复到另一个活动时立即关闭它。 很高兴这对您有所帮助。 ^-^

以上是关于如何在创建后通过更改活动来处理推送通知意图?的主要内容,如果未能解决你的问题,请参考以下文章

单击推送通知时对特定活动的意图。

从 android 推送通知单击启动时,意图数据未在活动中更新

从通知中导航到父活动

iPhone 重新上线后如何接收远程通知?

如何在android应用程序活动和非活动状态下处理推送通知

iOS 推送通知系统服务器