Activity的LaunchMode导致调用系统相册选取图片立即返回RESULT_CANCELED,data为null

转载注明出处:简书-十个雨点

如题,最近在做调用系统相册选取图片的功能时,发现在一些手机上就会出现这种问题,具体的现象是使用如下代码选取图片:

String IMAGE_UNSPECIFIED = "image/*";
int SELECTPHOTO=10086;
Intent intent=new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.putExtra(Intent.EXTRA_TITLE, "Pick a Pic");
intent.setType(IMAGE_UNSPECIFIED);
startActivityForResult(intent, SELECTPHOTO);

此时在onActivityResult()中会立即收到结果:resultCode=0,data=null。

而且最奇怪的是这个问题不是在所有手机上都出现的,也不一定在某些Android系统版本上都出现,比如据我所知,在4.4的酷派k1和6.0的小米3是会出现的,在6.0的三星s6e就不出现。

百度谷歌stackoverflow了许久也没找到答案,最后经过多番实验,发现的Activity的launchMode导致的:当android:launchMode=”singleInstance”时,就会出现,其他launchMode则不会

在小李子吃苹果的指导下,我又进行了一些探索:

一开始他说:被启动activity在另一个task栈时候都会立即返回,比如被启动activity指定了taskAffinity。

我关注的重点放到了是taskaffinity不同导致的,于是我试着设置了一下,发现:first启动second的时候,如果second设了taskAffinity,还必须把second设成singleTask或者singleInstance才会直接立刻返回;或者first设成singleInstance才会出现。还得是低版本(4.4)的手机,高版本(6.0,其他没尝试)不会出现。

然后通过百度,我又发现taskaffinity必须配合singleTask或者singleInstance,才会产生新task的效果(4.4)。而在高版本(6.0)上则还必须设置FLAG_ACTIVITY_NEW_TASK才行。

至于如何判断taskaffinity是否生效,可以使用

adb shell dumpsys activity

打印出Recent tasks查看。

于是自然就想到,是不是只要设置FLAG_ACTIVITY_NEW_TASK来启动就会出这个问题呢?简单尝试,发现果然如此!

因此可以得出最后的结论,只要startActivityForResult()的调用方和被调用方不在同一个task中,就会立刻返回cancel。而在低版本和高版本中,可能产生新task的条件不完全相同,所以也导致了差异性。至于为什么有这样的差异性,等以后我研究明白了再单开一篇说说。

最后贴一段代码,ActivityStarter中的:

private void sendNewTaskResultRequestIfNeeded() {
    if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
            && mStartActivity.resultTo.task.stack != null) {
        // For whatever reason this activity is being launched into a new task...
        // yet the caller has requested a result back.  Well, that is pretty messed up,
        // so instead immediately send back a cancel and let the new task continue launched
        // as normal without a dependency on its originator.
        Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
        mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
                mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
        mStartActivity.resultTo = null;
    }
}

阅读注释部分就可以发现跟我上面总结的一样的结论。

记录下来,方便万一有朋友遇到类似问题能搜到。

参考:

TaskAffinity属性小结

你可能感兴趣的:(Android)