Android应用Home键后Launcher重复启动问题

    通过系统方式(系统安装器)安装应用,点击“打开”按钮,进入应用主界面,按home键后,点击应用图标进入,应用会出现重新启动。当完全退出应用后,再通过启动图标进入应用,便不会出现重复启动问题。目前测试大部分Android机型均会出现此类问题。

重现方式

  1. 系统安装器安装APK(含覆盖安装),成功后点击“打开”按钮,进入应用。
  2. 应用正常启动为AAActivity,然后进入主页面MainActivity,此时进入二级页面A或三级页面B。
  3. 按home键,将程序置于后台。
  4. 在launcher上打开APP。
  5. 程序重新启动,先AAActivity后MainActivity。

    定位了问题重现方式,发现只是系统安装器安装后,会出现重复启动问题。因此检查安装器打开应用与launcher打开应用的不同,为此在首次启动页面AAActivity打印action,category,flags,TaskId,Pid信息。重复上述过程。
1.当通过安装器打开APP时,log信息如下:

AAActivity: 
getAction:android.intent.action.MAIN
getCategories:android.intent.category.LAUNCHER
getFlags:Intent.FLAG_ACTIVITY_NEW_TASK
TaskId:308,Pid:5445

2.按home键,launcher上打开APP,log信息如下:

AAActivity: 
getAction:android.intent.action.MAIN
getCategories:android.intent.category.LAUNCHER
getFlags:Intent.FLAG_ACTIVITY_NEW_TASK,Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
TaskId:308,Pid:5445

3.多次重复按home键,重复打开APP,log信息与2中相同,因此可以判断此时新建的AAActivity是压入之前的任务栈中。

4.完全退出应用程序,即销毁原有任务栈,launcher上打开APP,log信息如下:

AAActivity:
getAction:android.intent.action.MAIN
getCategories:android.intent.category.LAUNCHER
getFlags:Intent.FLAG_ACTIVITY_NEW_TASK,Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
TaskId:309,Pid:7150

结论

通过以上log信息可以确定以下结论:
1)AAActivity用安装器打开应用flag为FLAG_ACTIVITY_NEW_TASK,launcher打开应用比系统安装器多了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
2)用FLAG_ACTIVITY_NEW_TASK创建的任务栈,再用FLAG_ACTIVITY_RESET_TASK_IF_NEEDED(launcher方式)打开,会在AAActivity多了FLAG_ACTIVITY_BROUGHT_TO_FRONT
3)异常重复启动过程中,新建AAActivity的TaskId与Pid一致,可确定还是在原有任务栈中创建Activity,打开多次MainActivity(standard启动模式)会在原有任务栈中叠加。

解决方法

    在启动页(AAActivity)中通过isTaskRoot(Return whether this activity is the root of a task. The root is the first activity in a task.)方法来进行判断:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (!isTaskRoot()) {
            finish();
            return;
        }
 }

    判断逻辑为:判断启动页是否为当前任务栈的根Activity,如果不是根Activity则finish掉。语意上来讲,一个任务栈的根Activity应是启动页,这样也符合正常的应用场景;如果不是根Activity,那么说明出现了异常启动,应当将该启动页销毁掉,显示原有任务栈。
而此判断方法也是基于以上结论(3)来解决的,还有一种判断方式是基于结论(2),在AAActivity中判断是否含有FLAG_ACTIVITY_BROUGHT_TO_FRONT标志:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
            finish();
            return;
        }
 }

    先来看下API中对FLAG_ACTIVITY_BROUGHT_TO_FRONT标志位的解释:

  /**
     * This flag is not normally set by application code, but set for you by
     * the system as described in the
     * {@link android.R.styleable#AndroidManifestActivity_launchMode
     * launchMode} documentation for the singleTask mode.
     */
    public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 0x00400000;

    此标志位是singleTask 启动模式下,由系统进行设定的。但在测试过程中的AAActivity为standard启动模式,也会添加该标志位?关于这一点官方也没有一个明确的关于该标志位的说明。因FLAG_ACTIVITY_BROUGHT_TO_FRONT使用的未知性,以及AAActivity启动模式特殊性,最终还是选取用isTaskRoot()来进行判断。

    1.AAActivity中如果实现了finish() 和 onDestroy()方法,要保证这两个方法无空对象操作以及注销未注册的Service等类似操作。因为二次打开AAActivity在onCreate()方法中便finish()掉,可能涉及一些变量未初始化操作等。
    2.finish() 和 onDestroy()方法中不能调用System.exit(0);否则二次打开AAActivity杀掉进程时也会将之前任务栈活动杀掉。
    3.如果MainActivity为singleTask 启动模式(也符合一般应用场景),那么就会出现异常启动情况下新AAActivity打开原MainActivity并将MainActivity之上的其他Activity clear掉,因此展现给用户的就是再次点击launcher,会先进AAActivity,再进入保留原有活动的MainActivity。
    4.launcher打开应用比系统安装器多了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,证明添加了该标志位的栈,不会存在重复启动问题,这也符合API中该标志位如果存在一个已经存在的栈则会复用原栈的说明。


评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值