1. 程式人生 > >Activity的LaunchMode導致呼叫系統相簿選取圖片立即返回RESULT_CANCELED,data為null

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;
    }
}

閱讀註釋部分就可以發現跟我上面總結的一樣的結論。

記錄下來,方便萬一有朋友遇到類似問題能搜到。

參考: