? ? 最近开发个快捷启动某个功能的需求,需要用到安卓的Shortcuts,其中遇到个启动模式的坑,这里记录一下。
? ? 首先,Google提供的快捷方式有三种(详情见官方文档):
1. 静态快捷方式:7.1开始支持,在Manifest的Launcher Activity中注册;
2. 动态快捷方式:7.1开始支持,通过ShortcutManager动态添加、移除或更新;
3. 固定快捷方式:8.0开始支持,在启动器中显示为单独的图标,通过ShortcutManager申请添加。
? ?这里要讲的是静态快捷方式,静态快捷方式在xml下的xxx.xml文件中定义Intent,但是其启动模式(Intent Flag)是由系统自定义的,官方文档这一段话非常重要:
? ? 也就是说,系统启动我们在xxx.xml中定义的Activity时,会自动加上FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK标记,这样会导致一个问题:应用在运行时,此时启动快捷方式,会将应用的任务栈(特别是MainActivity)给清除掉,然后启动我们的快捷方式Acitivity。关于这两个Flag的介绍,我给贴一下,特别注意其中标红的部分:
FLAG_ACTIVITY_NEW_TASK
If set, this activity will become the start of a new task on this history stack. A task (from the activity that started it to the next task activity) defines an atomic group of activities that the user can move to. Tasks can be moved to the foreground and background; all of the activities inside of a particular task always remain in the same order. See?Tasks and Back Stack?for more information about tasks.
This flag is generally used by activities that want to present a "launcher" style behavior: they give the user a list of separate things that can be done, which otherwise run completely independently of the activity launching them.
When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in. See?FLAG_ACTIVITY_MULTIPLE_TASK ?for a flag to disable this behavior.
This flag can not be used when the caller is requesting a result from the activity being launched.
FLAG_ACTIVITY_CLEAR_TASK
If set in an Intent passed to?Context.startActivity() , this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with?FLAG_ACTIVITY_NEW_TASK .
? ? 一般情况下,这样处理也没多大问题,但是在有些情况下,MainActivity的启动是非常耗时的,将MainActivity给finish掉是难以接受的,那这种情况要怎么处理呢?
? ?其实官方已经给了一个思路,就是将快捷方式定义的Activity作为一个跳板,其taskAffinity定义为""(taskAffinity的缺省值是应用的包名,也就是将其启动在非缺省的任务栈),然后在这个跳板Activity(A)中启动要真正启动的Acitivity(B),示例代码如下所示:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate " + getTaskId() + " " + hashCode());
Intent intent = new Intent(this, ShortcutMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
overridePendingTransition(0, 0);
finish();
}
? ?注意A启动B的启动模式,由于A启动后处于taskAffinity=""的任务栈,而B需要回到主任务栈,所以需要标记FLAG_ACTIVITY_NEW_TASK,至于是否需要标记FLAG_ACTIVITY_CLEAR_TOP,则根据自己的需要。
FLAG_ACTIVITY_CLEAR_TOP
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B.
The currently running instance of activity B in the above example will either receive the new intent you are starting here in its onNewIntent() method, or be itself finished and restarted with the new intent. If it has declared its launch mode to be "multiple" (the default) and you have not set?FLAG_ACTIVITY_SINGLE_TOP ?in the same intent, then it will be finished and re-created; for all other launch modes or if?FLAG_ACTIVITY_SINGLE_TOP ?is set then this Intent will be delivered to the current instance's onNewIntent().
This launch mode can also be used to good effect in conjunction with?FLAG_ACTIVITY_NEW_TASK : if used to start the root activity of a task, it will bring any currently running instance of that task to the foreground, and then clear it to its root state. This is especially useful, for example, when launching an activity from the notification manager.
? ?注:上面的解决方案似乎并不复杂,但由于业务的复杂性(SDK开发受到诸多限制,Launcher Activity动不得,MainAcitivity动不得,还受到SDK的初始化问题的限制(核心SDK(仍然是动不得)设计问题,不能重复初始化...,甚至不能重复调用初始化接口)),再加上对不同任务栈的切换和Acitivity的启动模式的了解并不全面,这其间走了一些弯路,所以这里记录一下,共勉。
参考资料:
创建快捷方式 ?|? Android 开发者 ?|? Android Developers
Android7.1Shortcuts - 老弟,来啦? - OSCHINA - 中文开源技术交流社区
|