Fragment中调用startActivityForResult的那些坑

//FragmentActivity.class
public 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的requestCodewho通过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方法中调用ActivityCompatstartActivityForResult方法发起启动Activity的时候又把requestIndexrequestCode关联起来了

这样后面回调onActivityResult方法时就可以根据requestCode获取对应的Fragment,以便调用Fragment的onActivityResult方法

最后看一下ActivityCompatstartActivityForResult方法

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

@Override
protected 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);

最后

我这里整理了一份完整的学习思维以及Android开发知识大全PDF。

当然实践出真知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
知,即使有了学习线路也要注重实践,学习过的内容只有结合实操才算是真正的掌握。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 27
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值