问题现象:
在刚安装完demo应用未登录任何帐号时,通过系统内的分享功能想将文件/图片等内容"发送给好友"或"发送到我的电脑",触发登录界面,但登录成功后,没有跳转到选择demo好友发送界面,无法继续发送。本文为Sodino所有,转载请注明出处:http://blog.csdn.net/sodino/article/details/22101881
代码分析:
demo中JumpActivity处理着各种外部应用分享入口,通过调试发现进行分享时会判断是否登录过,如果未登录则会跳转至LoginActivity进行登录。如下代码:
private void doShare(booleancheckLogin) { // 系统级分享 Intent intent = getIntent(); ... ... ... ... // 没登录 if (checkLogin &&!demo.isLogin()){ Intent i = newIntent(this, LoginActivity.class); i.putExtra("isActionSend",true); i.putExtras(extra); i.putExtras(i); startActivityForResult(i,SHARE_LOGIN_REQUEST); return; } ... ... }
查阅代码得知登录成功后,则JumpActivity.onActivityResult()将会得到requestCode值为SHARE_LOGIN_REQUEST的回调。为此,在onActivityResult()回调处设置断点,再次跟进。
设置断点,执行分享操作进行调试,发现每次执行完startActivityForResult(),则onActivityResult()便立刻被回调了,且resultCode值为RESULT_CANCEL。至些,问题开始有了头绪。
通过排查,发现LoginActivity在之前有被改动过,其launchMode赋值为singleTask。分享功能就是在这次改动之后失效了的。只要恢复launchMode为standard,即可让onActivityResult()在LoginActivity登录成功后正常回调回来,执行分享操作,恢复功能。
至此,问题得到解决,但问题原因仍是一头雾水:
为什么通过startActivityForResult()方式去启动launchMode=singleTask的Activity,onActivityResult()会被立即回调且resultCode值为RESULT_CANCEL??
原因解析:
经查文档,发现文档中另一相似的方法startActivityForResult(Intent,int,Bundle)有说明如下:
Note that this method should only be used with Intent protocols thatare defined to return a result. In other protocols (such as ACTION_MAIN orACTION_VIEW), you may not get the result when you expect. For example,if the activity you are launching uses thesingleTask launch mode, it will not run in your task and thus you willimmediately receive a cancel result.
但这点注释让人理解得仍不是很透彻。继续搜索,发现文档(点击这里)里说了下面的这一种现象。
在下图中,存在着前两个栈,其中直接显示在屏幕上与用户交互的Back Stack,及另一个隐藏在后台的Background Task,该栈栈顶的Activity Y其launchMode为singleTask。
如果在Activity 2中调用BackgroundTask中已经启动过的Activity Y,则Background Task内占据屏幕并且该Task下所有的栈都会保留当前的栈位置及顺序push进Back Task形成新的结构,顺序由上至下为Activity Y→Activity X→Activity 2→Activity 1。
在Activity Y界面按返回键,则ActivityY出栈,Activity X占据屏幕!注意,由Activity2调用的Activity Y,但返回键后,回退显示的是Activity X!所以即使在Activity Y执行setResult(),Activity 2也是无法接收到的。换回文章开头的问题,即在JumpActivity处启动LoginActivity(已经被设置singleTask了),则LoginActivity的setResult()结果有可能不会传给JumpActivity。
继续按返回键,则才回到Activity 2。
问题结论:
由此,我们再回到先前的问题。在这种Tasks的入栈与出栈设计下,由于可能有Activity X的存在,所以在Activity 2启动Activity Y时,则直接回调了onActivityResult()并给出了RESULT_CANCEL也就可以理解了。
[Android]startActivityForResult启动singleTask的Activity,则onActivitResult()立即回调且resultCode为RESULT_CANCEL