【问题标题】:How to keep back stack with notification如何通过通知保留堆栈
【发布时间】:2016-12-27 17:22:28
【问题描述】:

我正在尝试呈现由不在正常应用程序流中的特殊活动处理的通知,并尝试让后台堆栈处理“正确”,意思是:

  1. 如果在应用程序运行时处理通知,则通知活动应该出现在当前堆栈上,从通知返回时应该离开我们在应用程序中的位置。请注意,这可能意味着应用程序已打开。
  2. 如果在应用程序未运行时处理通知,则通知活动应出现在应用程序的主(初始)活动中。

到目前为止,我用来呈现通知的代码是:

/**
 * Show (or update) a notification for the current message set.
 * 
 * @param showNotification true to use a high priority notification which will be immediately
 *                         displayed (as opposed to just added to the status bar)
 */
private void createOrUpdateNotification(boolean showNotification) {
    Message oldest = messages.get(0);
    Message newest = messages.get(messages.size() - 1);

    // Create the notification
    NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
            // Set notification data and appearance
            .setContentTitle(title)
            .setContentText(newest.message)
            .setSmallIcon(smallIcon)
            .setWhen(newest.when)
            .setColor(ContextCompat.getColor(context, R.color.primary_color))

            // Set notification options
            .setAutoCancel(true)
            .setCategory(NotificationCompat.CATEGORY_MESSAGE)
            .setPriority(showNotification ? NotificationCompat.PRIORITY_HIGH : NotificationCompat.PRIORITY_LOW)
            .setDefaults(NotificationCompat.DEFAULT_VIBRATE)
            .setOnlyAlertOnce(!showNotification);

    // Set up the action if the first (oldest) message has an intent builder
    if(oldest.intent != null) {
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context.getApplicationContext());
        stackBuilder.addNextIntent(oldest.intent);
        builder.setContentIntent(stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT));
    }

    NotificationManagerCompat.from(context).notify(notificationId, builder.build());

    Log.i("notification created");
}

为了澄清,Message.intent 是一个单一的意图,配置为打开通知处理活动。

我的问题是,如果应用程序当前正在运行并在打开通知时打开,则应用程序关闭并且通知显示在一个空堆栈上并且应用程序的后堆栈被清除。

我的理解是,如果内容意图是包含单个意图的待处理意图,则所需的行为应该是自动的,这里就是这种情况。

我错过了什么?

【问题讨论】:

  • 我是否正确理解了您的问题?您想显示通知并在显示通知时停止发出通知的线程?这就是你想要的吗?
  • 没有。通知由服务生成。内容操作会打开一个超出正常应用程序流程的活动。当该活动被解除时,我想回到被中断的拥有应用程序活动。
  • 你解决了吗?我有同样的问题。

标签: android android-notifications back-stack


【解决方案1】:

TaskStackBuilder.create 将启动一个新的任务堆栈。

改为这样设置内容意图:

builder.setContentIntent(
  PendingIntent.getActivity(
    context, 
    0, 
    oldest.intent, 
    PendingIntent.FLAG_UPDATE_CURRENT
));

【讨论】:

  • 谢谢,这很接近!在这一点上唯一缺少的是,如果我在生成通知之前一直回到启动屏幕(在我的应用程序之外),那么应用程序根本不会启动,只是通知。
  • 您可以覆盖通知活动的 onBackPressed() 并调用 isTaskRoot()。如果通知活动是任务根,那么您可以启动您的主要活动。
  • 这里是棘手的部分,这一切都来自一个 SDK(我不拥有宿主应用程序)有没有一种方便的方法来启动应用程序的默认活动?
  • 请问您使用的是哪个SDK?如果您知道活动的完全限定名称(包名和类名),则可以启动主要活动。您传递给待处理意图的意图(即,oldest.intent)必须引用主要活动。
【解决方案2】:

为了扩展@leco 的答案,我的最终解决方案有两个部分。

首先是按照他的建议构建Notification,直接使用PendingIntent,而不是尝试使用TaskStackBuilder

builder.setContentIntent(
  PendingIntent.getActivity(
    context, 
    0, 
    oldest.intent, 
    PendingIntent.FLAG_UPDATE_CURRENT
));

如果应用程序正在运行但当前未打开(即,直到用户完全退出应用程序),这让我得到了正确的行为

为了获得“正确”的行为,我修改了我的Notification处理活动,覆盖finish()

public void finish() {
    if(isTaskRoot()) {
        // If we're the task root, probably because we were launched from a notification with the
        //  application closed, we should just open the default activity
        try {
            String homeClassName = getPackageManager().queryIntentActivities(
                    new Intent(Intent.ACTION_MAIN).setPackage(getApplicationContext().getPackageName()),
                    0
            ).get(0).activityInfo.name;

            Class homeClass = Class.forName(homeClassName);

            getApplicationContext().startActivity(new Intent(getApplicationContext(), homeClass).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
        }
        catch(Exception exception) {
            Log.w(String.format("Can't find the MAIN activity for package %s", getApplicationContext().getPackageName()));
        }
    }
    super.finish();
}

queryIntentActivities 等的旋转是由于我实际上正在为应用程序开发一个插入式组件,所以我实际上并不知道它们的 root/home/launch 活动实际上是什么。我尝试了一种更简单的方法来构建一个 HOME 意图:

startActivity(new Intent(Intent.ACTION_MAIN).setPackage(getApplicationContext().getPackageName())

但由于某种原因,startActivity 抛出了异常:

android.content.ActivityNotFoundException: No Activity found to handle Intent

尽管queryIntentActivities 方法表明Intent 存在适当的Activity

【讨论】:

    【解决方案3】:

    创建一个 Bundle 队列,并根据您的要求不断从队列中添加和删除 Bundle 对象。

    /**
         * Queue that holds notifications messages
         */
        private Queue<Bundle> mNotificationQueue = new LinkedList<Bundle>();
    
    /**
    * Method returning the singleton queue maintained in a static class  
    */
     public Queue<Bundle> getNotificationQueue() {
            return mNotificationQueue;
        }
    

    现在当收到通知时,将通知消息添加到队列中

    // Fetching the message from intent and adding in bundle to add in the queue
    
    Bundle notificationMsgBundle = intent.getExtras();
    
    notificationMsgBundle.getString(MyConstants.KEY_CHANNEL) + " :: " + notificationMsgBundle.getString(MyConstants.KEY_DATA));
    

    DataManager.getInstance().getmNotificationQueue().add(notificationMsgBundle)

    现在这个静态队列在整个应用程序中得到维护,您可以从队列中删除或添加消息

    // removing the node message in the queue as per requirement
     DataManager.getInstance().getmNotificationQueue().remove();
    

    【讨论】:

      猜你喜欢
      • 2010-09-13
      • 2023-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-03
      • 1970-01-01
      • 1970-01-01
      • 2012-09-21
      相关资源
      最近更新 更多