【问题标题】:Notification to restore a task rather than a specific activity?通知恢复任务而不是特定活动?
【发布时间】:2011-07-04 20:17:34
【问题描述】:

我有一个前台服务,只要用户登录到应用程序,它就会与服务器保持连接。这样可以使连接保持活动状态,并且可以直接从服务器接收消息,即使用户按 Home 已将应用程序发送到后台。

应用程序有许多活动,当它被发送到后台时,其中任何一个都可能是活动的。

我想允许用户点击通知来恢复当前的活动。我了解如何恢复特定活动,但想知道是否有办法恢复用户上一个活动?当然我可以跟踪最后一个,然后从 Notification 回调中调用它,但认为在任务级别可能有办法?

感谢您提供的任何建议。

【问题讨论】:

    标签: android android-activity notifications


    【解决方案1】:

    您需要的只是一个什么都不做的简单 Activity。这是一个例子:

    public class NotificationActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // Now finish, which will drop the user in to the activity that was at the top
            //  of the task stack
            finish();
        }
    }
    

    设置您的通知以开始此活动。确保在清单中此活动的任务亲和性与您应用程序中其他活动的任务亲和性相同(默认情况下,如果您没有明确设置 android:taskAffinity) .

    当用户选择此通知时,如果您的应用程序正在运行,那么 NotificationActivity 将在您应用程序任务中的最顶层活动的顶部启动,并且该任务将被带到前台。当 NotificationActivity 完成时,它只会将用户返回到应用程序中最顶层的活动(即:当它进入后台时用户离开它的地方)。

    如果您的应用程序尚未运行,这将不起作用。但是,您有 2 个选项来处理这个问题:

    1. 确保在您的应用程序未运行时通知栏中不存在通知。

    2. 在 NotificationActivity 的 onCreate() 方法中,检查您的应用程序是否正在运行,如果没有运行,请调用 startActivity() 并启动您的应用程序。如果这样做,请务必在启动应用程序时设置标志 Intent.FLAG_ACTIVITY_NEW_TASK,以便任务的根 Activity 不是 NotificationActivity。

    【讨论】:

    • 很好的答案谢谢@DavidWasser
    • 效果很好,但愚蠢的是,这个 hack 是解决这个问题的唯一可靠解决方案。没有多少意图标志可以简单地跨 API 16+ 可靠地从最近的应用程序列表中恢复应用程序。
    • 今天这仍然是最好的主意吗?
    • @ArchieG.Quiñones 一般来说,更好的解决方案是使用“启动器Intent”,您可以通过调用PackageManager.getLaunchIntentForPackage("my.package.name") 获得它,但是这种解决方案并非在所有情况下都有效,它可以如果它不起作用,则很难调试。我的答案中的解决方案应该始终有效,因为它不依赖于特殊的 Intent 标志或启动模式。
    • 一直在寻找这个。这是需要在文档中的解决方案。非常感谢!
    【解决方案2】:

    效果很好,谢谢大卫!下面的类检查应用程序是否已经在运行,如果没有,则在完成之前启动它(正如 David 在选项 2 中所建议的那样)。

    public class NotificationActivity extends Activity 
    {
        @Override
        protected void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
    
            // If this activity is the root activity of the task, the app is not running
            if (isTaskRoot())
            {
                // Start the app before finishing
                Intent startAppIntent = new Intent(getApplicationContext(), MainActivity.class);
                startAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(startAppIntent);
            }
    
            finish();
        }
    }
    

    【讨论】:

    • 为 isTaskRoot() 方法点赞。
    【解决方案3】:

    有一个更简单的解决方案,不需要额外的活动。有关详细信息,请参阅this post。基本上,通知启动(可能存在的)任务的方式与您在应用程序处于后台时单击启动器图标时启动的方式相同。

    【讨论】:

    • 实际上,这个想法本身对我来说在 Android API 23 上并不可靠
    【解决方案4】:

    我的解决方案,它模拟启动器的行为(将任务带到前台):

    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.addCategory(Intent.CATEGORY_LAUNCHER);
    intent.setClassName(MyApplication.class.getPackage().getName(), MainActivity.class.getName());
    

    【讨论】:

      【解决方案5】:
      Intent intent = new Intent(Intent.ACTION_MAIN);
      intent.addCategory(Intent.CATEGORY_LAUNCHER);
      

      这行得通,毫无疑问,但问题是当您将意图设置为 ACTION_MAIN 时。然后,您将无法为意图设置任何捆绑包。我的意思是,您的原始数据将不会从目标活动中收到,因为 ACTION_MAIN 不能包含任何额外的数据。

      您可以将您的活动设置为 singleTask 并正常调用您的意图而不设置 ACTION_MAIN 并从目标活动的 onNewIntent() 方法接收意图。

      但请注意,如果您调用 super.onNewIntent(intent);然后将创建该活动的第二个实例。只是不要调用超级方法。

      【讨论】:

      • 是的!谢谢你。出于某种奇怪的原因需要setAction 以允许不同的通知转到不同的类,因此需要您的解决方案。
      【解决方案6】:

      我结合了 David Wasser 和 Raginmari 的解决方案,通过对应用的根 Activity 执行该方法,那么当您的应用已经启动或尚未启动时,它都适用于这两种情况。

      public class YourRootActivity extends Activity 
              {
                  @Override
                  protected void onCreate(Bundle savedInstanceState) 
              {
                  super.onCreate(savedInstanceState);
          
                  if (!isTaskRoot()) // checks if this root activity is at root, if not, we presented it from notification and we are resuming the app from previous open state
                  {
                       val extras = intent.extras // do stuffs with extras.
                       finish();
                       return;
                  }
                   // OtherWise start the app as usual
              }
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多