测试同学近日在测试中发现了这么一个Bug,复现步骤如下:
- 打开应用
- 任意开启一个页面
- Home键回退到Launcher
- 重装应用
- 打开应用
- 任意开启一个页面
- Home键回退到Launcher
- 点击应用图标启动应用
- Bug出现了:此时应用并没有如预期般直接将Task带到前台,而是开屏页一闪而过,然后就回到了应用的主页面
我们知道,每次发起Intent导致新创建Task的时候,该Task会记录该Intent的信息;如果后续有一个新的Intent出现并与该Task的启动Intent完全一致(启动类,action、category等等全部一样,不可多项也不可缺少),那么该Intent并不会触发Activity的新建与启动,而只会将已经存在的Task移到前台。
那么为什么会出现如bug所述那样的问题呢?下面按照Bug浮现步骤来捋一捋:
首先定义一下,L为Launcher,P1为开屏页,P2为主页面,P3为任意一个其他页面。不同task用|分割,相同task的页面用/分割。
- 打开应用:L -> L|P1|P2 -> L|P2
- 任意开启一个页面:L|P2/P3
- Home键回退到Launcher:P2/P3|L
- 重装应用:L
- 打开应用:L -> L|P1|P2 -> L|P2
- 任意开启一个页面:L|P2/P3
- Home键回退到Launcher:P2/P3|L
- 点击应用图标启动应用,Bug复现
OK,这里我们看到的现象是,一个新的Task被创建了,并且新的页面立刻就销毁了,然后由于以singleTask启动主页面的时候发现已经存在了这个Task,于是把原来的Task立刻带到了前台,并出栈了所有栈顶的页面:
- 启动:P2/P3|L -> P2/P3|L|P1
- 以singleTask启动新的P2,退出P1,将原有的P2/P3带到前台并将P3出栈:P2/P3|L|P1 -> L|P2
回想我们之前提到过的一个很重要的一点:如果创建Task的Intent和某个期望启动应用的Intent一模一样,那么该Task会被带到前台,否则会重新创建Task。那么这里会不会是在这里出问题呢?
我仔细回想了Bug的复现步骤,发现在「5. 打开应用」这一步中遗漏了一个非常重要的细节:我们似乎是在安装完应用之后直接点击「打开应用」启动的应用 —— 问题就出在这里,「打开应用」对应的Intent和Launcher中的Intent其实是不一致的——至少在某些方面是无法匹配的,那么通过这种方式启动的Task和点击Launcher图标启动的Task自然是无法相容了,出现Bug中的现象也就解释的通了。
为了验证想法的正确性,我再次重复了一次上述的步骤,只不过在第五步「5. 打开应用」中,并没有直接点击「打开应用」,而是退回到桌面,点击Launcher中应用的icon来启动应用。果然,这一次没有再发生之前的问题。
那么,我们该如何在应用中防止这种状况的发生呢?在网上寻求解答的时候发现了这篇文章,他也遇到了和我一样的问题,而他的解决思路则是在开屏页另外发起一个与Launcher相同的Intent请求启动应用。这个方法是否有效以及有没有副作用这里不做探讨也没有尝试过,如果有读者(哦我的文章没有读者)感兴趣的话,可以自己试一试嗯。
这是次很神奇可能也很微妙的Bug复现及追踪记录,这个问题并不算什么大问题,但是在追踪这个问题的过程中也让我对于App的启动方式有了新的理解,所以这里稍微记录一下,留以存档。