Fragment 中调用 startActivityForResult 的那些坑,安卓面试题目 2019
int requestIndex = mNextCandidateRequestIndex;
//将 requestIndex 和 fragment 的 mWho 保存起来 mPendingFragmentActivityResults.put(requestIndex, fragment.mWho);mNextCandidateRequestIndex =(mNextCandidateRequestIndex + 1) % MAX_NUM_PENDING_FRAGMENT_ACTIVITY_RESULTS;
return requestIndex;}
这里allocateRequestIndex方法就把requestIndex和 Fragment 的mWho变量关联起来了
在上面的`startActivityFromFra
gment方法中调用ActivityCompat的startActivityForResult方法发起启动Activity的时候又把requestIndex和requestCode`关联起来了
这样后面回调onActivityResult方法时就可以根据 requestCode 获取对应的 Fragment,以便调用 Fragment 的onActivityResult方法
最后看一下ActivityCompat的startActivityForResult方法
public static void startActivityForResult(@NonNull Activity activity, @NonNull Intent intent,int requestCode, @Nullable Bundle options) {if (Build.VERSION.SDK_INT >= 16) {activity.startActivityForResult(intent, requestCode, options);} else {activity.startActivityForResult(intent, requestCode);}}
(2)onActivityResult方法回调
通过断点调试的方法,我们会发现最先被回调的就是父 Activity 的onActivityResult,也就是我们的 FragmentActivity 的onActivityResult
@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {mFragments.noteStateNotSaved();int requestIndex = requestCode>>16;//requestIndex = 0 就表示没有 Fragment 发起过 startActivityForResult 调用 if (requestIndex != 0) {requestIndex--;
//根据 requestIndex 获取 Fragment 的 who 变量 String who = mPendingFragmentActivityResults.get(requestIndex);mPendingFragmentActivityResults.remove(requestIndex);if (who == null) {Log.w(TAG, "Activity result delivered for unknown Fragment.");return;}
//然后根据 who 变量获取目标 FragmentFragment targetFragment = mFragments.findFragmentByWho(who);if (targetFragment == null) {Log.w(TAG, "Activity result no fragment exists for who: " + who);} else {//最后调用 Fragment 的 onActivityResulttargetFragment.onActivityResult(requestCode & 0xffff, resultCode, data);}return;}
...super.onActivityResult(requestCode, resultCode, data);}
从上面的方法中可以看出 FragmentActivity 中的onActivityResult方法中对于 Fragment 的startActivityForResult调用已经做了处理。
这里就有一个问题需要注意了,我们一般都会覆写父 Activity 中的onActivityResult方法,这个时候我们必须在onActivityResult方法加上super.onActivityResult(),否则 Fragment 中的onActivityResult方法就没有办法回调到了。
这就是文章开头中提到的 2、3 两点需要注意的原因
getParentFragment 发起调用
这种情况一般发生在嵌套多层 Fragment 的时候
getParentFragment 发起调用的过程和上面的类似,只不过发起调用的是当前 Fragment 的父 Fragment,所以最后回调的也是父 Activity 的onActivityResult方法和父 Fragment 的onActivityResult方法。
所以如果想在子 Fragment 中监听到onActivityResult方法的回调,就不要用这种方式
getActivity 方法发起调用
这个就更简单了,直接调用的是父 Activity 的onActivityResult方法
//FragmentActivity.class@Overridepublic void startActivityForResult(Intent intent, int requestCode) {// If this was started from a Fragment we've already checked the upper 16 bits were not in// use, and then repurposed them for the Fragment's index.if (!mStartedActivityFromFragment) {if (requestCode != -1) {checkForValidRequestCode(requestCode);}}super.startActivityForResult(intent, requestCode);}
所以从源码也可以看出,这种方式最后不会回调 Fragment 的onActivityResult方法
总结
在 Fragment 中调用startActivityForResult以及监听onActivityResult是很常见的一种应用方式,但是稍不注意就会掉到坑里,比如因为Activity的onActivityResult方法没有调用super.onActivityResult()方法而导致 Fragment 中死活接收不到onActivityResult的回调。
最后总结一下几种场景的应用步骤:











 
    
评论