用getActivity方法发起调用,只有父Activity的onActivityResult会调用,Fragment中的onActivityResult不会被调用
直接发起startActivityForResult调用,当前的Fragment的onActivityResult,和父Activity的onActivityResult都会调用
用getParentFragment发起调用,则只有父Activity和父Fragment的onActivityResult会被调用,当前的Fragment的onActivityResult不会被调用。
这里2和3的前提是如果父activity中重写了
onActivityResult
,父Activity的onActivityResult
中必须添加super.onActivityResult()
总结起来就是:从哪里发起调用,最终就会走到哪里。
源码分析
Fragment中直接调用startActivityForResult
(1)发起startActivityForResult
调用
这种情况会直接调用到Fragment的startActivityForResult
方法
//Fragment.classpublic void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { if (mHost == null) { throw new IllegalStateException("Fragment " + this + " not attached to Activity"); } mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode, options); }
上面的mHost
对应的就是Fragment的父FragmentActivity
,所以会调用到父FragmentActivity
的startActivityFromFragment
方法
//FragmentActivity.classpublic void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) { mStartedActivityFromFragment = true; try { //一般requestCode都不会为-1,所以不会走if里面 if (requestCode == -1) { ActivityCompat.startActivityForResult(this, intent, -1, options); return; } //这里检查requestCode是否越界了,不能超过2^16 checkForValidRequestCode(requestCode); //根据这个requestIndex可以获取到对应Fragment的唯一标识mWho int requestIndex = allocateRequestIndex(fragment); //发起startActivityForResult调用,这里requestIndex和requestCode关联起来 ActivityCompat.startActivityForResult( this, intent, ((requestIndex + 1) << 16) + (requestCode & 0xffff), options); } finally { mStartedActivityFromFragment = false; } }
每一个Fragment在内部都有一个唯一的标识字段who
,在FragmentActivity
中把所有调用startActivityFromFragment
方法的fragment的requestCode
和who
通过key-value的方式保存在mPendingFragmentActivityResults
变量中
private int allocateRequestIndex(Fragment fragment) { ... 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
变量关联起来了
在上面的startActivityFromFragment
方法中调用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变量获取目标Fragment Fragment targetFragment = mFragments.findFragmentByWho(who); if (targetFragment == null) { Log.w(TAG, "Activity result no fragment exists for who: " + who); } else { //最后调用Fragment的onActivityResult targetFragment.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@Override public 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
的回调。
最后总结一下几种场景的应用步骤:
(1)一个Activity嵌套一层Fragment,Fragment中需要监听onActivityResult返回结果
直接在Fragment中调用
startActivityForResult
方法如果父Activity中覆写了
onActivityResult
,则需要确保调用了super.onActivityResult()
方法Fragment中实现onActivityResult方法即可监听回调结果
(2)一个Activity嵌套多层Fragment,Fragment中需要监听onActivityResult返回结果
这种情况和上面的是一样的,从上面的源码中我们可以看到,在哪个Fragment发起的
startActivityForResult
调用,只要父Activity的onActivityResult
方法调用了super.onActivityResult()
方法,Fragment中的onActivityResult
方法就会回调
其实,说白了就是在Fragment中直接调用
startActivityForResult
方法就行,不要用getActivity().startActivityForResult()
,也不要用getParentFragment().startActivityForResult()
,除非你知道为什么非要用这2种方式!
作者:xxq2dream
链接:https://www.jianshu.com/p/6311485ad771
共同学习,写下你的评论
评论加载中...
作者其他优质文章