不使用 android:launchMode="singleTask" 在新任务中打开 Android 活动

10

我已经创建了一个浏览器应用程序,其中主要活动响应以下意图:

 <intent-filter> 
       <data android:scheme="http"/>
       <data android:scheme="https"/>
       <category android:name="android.intent.category.DEFAULT"/>
       <category android:name="android.intent.category.BROWSABLE"/>
       <action android:name="android.intent.action.VIEW"/>
 </intent-filter>

当我从其他任务(如gmail、短信)点击链接并选择我的应用程序时,活动将在与调用任务相同的任务中打开。 当我选择不同的浏览器(Mozila Firefox、Chrome、Dolphine)时,它们会在不同的任务中打开。

查看其他浏览器清单,我发现没有一个使用android:launchMode="singleTask"

我不想使用singleTask标志,因为这不被谷歌推荐,并且会造成其他问题。

我试图理解其他浏览器是如何做到的,但没弄明白。

有什么想法吗?有没有其他方法可以在不使用singleTask标志的情况下在不同的任务中打开我的活动?


1
或许你可以在启动活动的意图上设置一个标记: Intent.FLAG_ACTIVITY_NEW_TASK 或者 Intent.FLAG_ACTIVITY_SINGLE_TOP 查阅文档: http://developer.android.com/guide/components/tasks-and-back-stack.htmlhttp://developer.android.com/reference/android/content/Intent.html - Guy S
不行,因为发送该活动的应用程序不是我的(例如 Gmail)。 - user3398598
1
@user3398598,Guy的建议很有道理:你应该将它与Emanuel的答案结合起来-请看我的评论。我知道你已经实现了一个解决方法,但我认为这种方法更简单,仅供参考。 - Stan
3个回答

2

您可以在onCreate中检查Activity是否在单一任务中运行。如果不是,请使用FLAG_ACTIVITY_NEW_TASK完成它并重新创建它。

这可能会对您有所帮助。

   ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);

    for (RunningTaskInfo task : tasks) {
        if (ctx.getPackageName().equalsIgnoreCase(task.baseActivity.getPackageName())) 
          // check if it's the only one activity or whatever                               
    }

感谢您的回答,getRunningTasks仅供调试使用,请参见:http://developer.android.com/reference/android/app/ActivityManager.html#getRunningTasks(int)。 - user3398598
1
这是最好的方法,但应该简化:没有必要检查正在运行的任务。只需在onCreate方法中检查getData()是否为null,如果不为null,则通过自定义extra将Uri传递给新实例,并使用FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK重新启动活动,然后finish()当前实例。我相信其他浏览器也是这样工作的。 - Stan

2
我在Android开发者网站上找到了以下描述:

例如,Android浏览器应用程序声明Web浏览器活动始终应在其自己的任务中打开——通过在<activity>元素中指定singleTask启动模式。这意味着,如果您的应用程序发出打开Android浏览器的意图,则其活动不会放置在与您的应用程序相同的任务中。相反,要么为浏览器启动新任务,要么(如果浏览器已在后台运行一个任务)将该任务提前处理新意图。

如您所见,android:launchMode=singleTask是您的正确选择。您已经提到了使用此属性时遇到的问题,因此让我们重点关注它们。 更新于2014年5月28日 Google关于singleTask启动模式的说明:

其他模式——singleTask和singleInstance——对大多数应用程序不适用,因为它们会产生用户不熟悉并且与大多数其他应用程序非常不同的交互模型。

谷歌的singleTask和singleInstance使用案例:
“专门的启动方式(不建议普遍使用)”
可以看出,singleTask可能并不适合普通用途,但是您的情况并不普遍,实际上它正是singleTask完美适用的情况之一。换句话说,singleTask并不是被禁止使用的,只需要小心使用,以便为最终用户提供与您的应用程序相同的体验。
我希望现在对您清楚了。在您的情况下,可以放心使用这种启动模式。

我已经尝试过了(将我的包ID作为Affinity),但它没有起作用。我认为这是因为我的任务还没有启动,所以活动将在调用任务中打开。 - user3398598
两个指示:第一,在任务管理器中,我只看到一个任务(消息任务),当点击它时,我看到我的活动。第二,在“运行活动”中运行“adb shell dumpsys activity”,我看到一个任务有两个活动:mms和我的活动。 - user3398598
没问题。你记得在亲和性(affinity)设置allowTaskReparenting了吗?你能解释一下为什么需要将你的活动放在单独的任务中吗?也许我们可以为最初的原因想出另一个解决方案。 - Damian Petla
是的,我设置了allowTaskReparenting标志。正如我在原始问题中所写的那样,我希望我的应用程序像其他浏览器一样运行,但是查看其他浏览器清单时,似乎没有人设置android:launchMode="singleTask"。 - user3398598
嗨Loop,你有其他的想法吗? - user3398598
显示剩余5条评论

1

您试图“打破规则”,并且不清楚通过不使用android:launchMode="singleTask"要避免什么。因此,我建议您研究以下两种方法:

  1. 创建一个Service并使该Service侦听意图过滤器。然后让此Service打开您的Activity,并将Activity的亲和性正确设置为与Service的匹配。这将允许您解决亲和性未正确绑定Activity的问题。

  2. 使用静默Activity启动新的Activity并退出。静默Activity将在新堆栈(而不是在单个任务模式下)中启动,并在启动实际需要的Activity后关闭自身。


服务如何监听意图过滤器?只有通过活动才能实现。 - Lester
最简单的方法是使用IntentService - http://developer.android.com/reference/android/app/IntentService.html。 模板化的方法是使用BroadcastReceiver - https://dev59.com/cW855IYBdhLWcg3wPBpx。 - Vaiden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接