【问题标题】:Resume application and stack from notification从通知中恢复应用程序和堆栈
【发布时间】:2011-07-27 00:33:06
【问题描述】:

我想以与用户在启动器中点击其图标完全相同的方式从状态栏通知恢复我的应用程序。

也就是说:我希望堆栈处于与用户离开之前相同的状态。

在通知上设置待处理 Intent 时的问题是它总是针对特定活动。我不想要这个。我需要像启动器一样恢复应用程序。

所以如果用户在活动A中,我想恢复活动A。如果他已经从活动A启动了活动B,那么我希望在用户点击通知时显示B,并且要恢复堆栈所以当用户点击 B 中的后退按钮时,A 会恢复。

还有其他几个标题相似的问题,但没有一个能解决我的问题。

【问题讨论】:

标签: android


【解决方案1】:

终极解决方案:Notification to restore a task rather than a specific 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
        }
    }

【讨论】:

    【解决方案2】:

    对于您不希望/无法对启动器活动进行硬编码的情况,此解决方案有效

    Intent i = getPackageManager()
        .getLaunchIntentForPackage(getPackageName())
        .setPackage(null)
        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
    
    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, i, 0);
    
    return new NotificationCompat.Builder(context)
            ...
            .setContentIntent(pendingIntent)
            .build();
    

    setPackage(null) 部分在我的情况下是关键,因为没有它,应用程序不会恢复到之前的任务。我将我的意图与 Android 启动器中的意图进行了比较,发现 pkg 没有在那里设置,因此我想出了从意图中删除包名称的方法。

    我的特殊情况是通知是在库中创建的,因此我无法知道启动器活动是什么。

    【讨论】:

    • 完美运行。但在我的情况下,我需要传递一些数据,它在应用程序完全退出并能够在 onCreate - Intent 中获取数据的情况下工作正常,而我无法从应用程序在后台运行的 Intent 获取数据。请问
    • 它看起来是唯一可行的解​​决方案,但你设置 FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 是为了什么?
    • 谢谢你,托马斯。经过数小时的奋斗,你救了我。
    • @Prat 用于应用运行,您将在 onNewIntent() 中获取数据 - 更多信息developer.android.com/reference/android/app/…
    • 终于得到了一个按预期工作的答案,它完美无缺!无论如何指定活动没有意义,所以即使其他解决方案有效,这个更清晰!
    【解决方案3】:

    只需使用 Android 在启动应用时使用的相同意图过滤器:

    final Intent notificationIntent = new Intent(context, YourActivity.class);
    notificationIntent.setAction(Intent.ACTION_MAIN);
    notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
    notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    

    由于您创建的用于从通知栏中打开Activity 的Intent 与用于启动您的应用的Android 相同,因此将显示之前打开的Activity,而不是创建新的Activity。

    【讨论】:

    • 只是一个问题:如果特定/替代启动器使用稍微不同的意图怎么办?也许还有其他一些附加功能或类别.. 你认为我应该缓存我的应用程序启动时的原始意图(由 Activity.getIntent() 检索),并按原样使用它来创建我的待处理意图吗?
    • 我为我工作,我有两个 activate splash 和 mainactivity,在用上面的代码修改我的代码后,它恢复 mainactive 而不开始新的活动。非常感谢你..
    • 它对我不起作用请任何帮助。我正在尝试使用nexus 5。
    • 尝试使用棒棒糖,但它不起作用。只需打开一个新的“YourActivity”
    • 有什么办法可以做到这一点,并且还可以传递新的附加信息吗?
    【解决方案4】:
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.REORDER_TASKS" />
    
    private void bringApplicationToForeground(){
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    
          List<ActivityManager.AppTask> tasksList = am.getAppTasks();
          for (ActivityManager.AppTask task : tasksList){
            task.moveToFront();
          }
        }else{
    
          List<ActivityManager.RunningTaskInfo> tasksList = am.getRunningTasks(Integer.MAX_VALUE);
          if(!tasksList.isEmpty()){
            int nSize = tasksList.size();
            for(int i = 0; i < nSize;  i++){
              if(tasksList.get(i).topActivity.getPackageName().equals(getPackageName())){
                am.moveTaskToFront(tasksList.get(i).id, 0);
              }
            }
          }
        }
    }
    

    【讨论】:

      【解决方案5】:

      我也遇到了同样的问题,并尝试像@GrAnd 的回答一样解决问题:

      final Intent notificationIntent = new Intent(context,YourActivity.class);
      Intent intent = new Intent(Intent.ACTION_MAIN);
      intent.addCategory(Intent.CATEGORY_LAUNCHER);
      

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

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

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

      【讨论】:

        【解决方案6】:

        创建一个活动,然后设置类别和相应的标志... 这就是我的工作方式,我必须这样做,因为我这样做是为了支持 Api lvl 8

        intent.addCategory(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.setClass(this, YourActivity.class);
        
        intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT|
                        Intent.FLAG_ACTIVITY_SINGLE_TOP);
        
        PendingIntent pi = PendingIntent.getActivity(this, 0, intent, 
                           PendingIntent.FLAG_UPDATE_CURRENT);
        

        在 AndroidManifest 中

        android:launchMode="singleTask"
        

        所以诀窍在于 Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT 以及清单中设置的行。

        希望对其他人有所帮助。

        【讨论】:

        • Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT 什么都不做,不推荐android:launchMode="singleTask",即使在方向和其他配置更改期间也不会重新创建活动
        • 你试过 API 8 级吗? 6年过去了,我想很多都变了。顺便说一句,将其标记为无用是很粗鲁的。
        【解决方案7】:

        这很简单 打开您的清单文件并在您的活动属性中设置属性启动模式 singleTop

        【讨论】:

        • 你在什么 API 上测试过这个?它似乎不适用于 API 23。按“返回”然后单击通知会启动活动的第二个实例
        【解决方案8】:

        可能有更简单的方法,但是您可以将数据存储在 sqlite 数据库中,并且每当您重新启动应用程序时,您可以检索保存到数据库中的任何状态并将您的值设置为它们需要的值。

        【讨论】:

        • 不,不,不。只是没有;)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多