Fragment.startActivityForResult不回调onActivityResult

本文深入探讨了在Android开发中,Fragment使用startActivityForResult启动Activity并接收返回数据的机制。详细分析了为什么直接通过Activity启动会导致onActivityResult方法不被回调的问题,并解释了Fragment内部对requestCode的特殊处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

前段时间在开发中遇到一个问题,在Fragment中启动一个Activity并返回数据,但是结果并没有回调onActivityResult方法,代码很简单应该没什么问题呀。在网上查资料,都是说是因为调用activity.startActivityForResult造成的,应该fragment.startActivityForResult,试了下发现确实可以解决问题,但是原理是什么呢?

原理

我们在Activity重写onActivityResult,发现是会回调onActivityResult的,那么肯定是内部做了什么特殊的处理,于是我查看FragmentActivity中的onActivityResult代码:

@Override
    @CallSuper
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        mFragments.noteStateNotSaved();
        int requestIndex = requestCode>>16;
        if (requestIndex != 0) {
            requestIndex--;

            String who = mPendingFragmentActivityResults.get(requestIndex);
            mPendingFragmentActivityResults.remove(requestIndex);
            if (who == null) {
                Log.w(TAG, "Activity result delivered for unknown Fragment.");
                return;
            }
            Fragment targetFragment = mFragments.findFragmentByWho(who);
            if (targetFragment == null) {
                Log.w(TAG, "Activity result no fragment exists for who: " + who);
            } else {
                targetFragment.onActivityResult(requestCode & 0xffff, resultCode, data);
            }
            return;
        }
        ActivityCompat.PermissionCompatDelegate delegate =
                ActivityCompat.getPermissionCompatDelegate();
        if (delegate != null && delegate.onActivityResult(this, requestCode, resultCode, data)) {
            // Delegate has handled the activity result
            return;
        }

        super.onActivityResult(requestCode, resultCode, data);
    }

在代码中可以看出,回调会先调用Activity中的onActivityResult,如果requestIndex != 0会调用Fragment中的onActivityResult,既然没有回调,那么可能是requestIndex!=0不成立,那么就断点调试一下:

activity.startActivityForResult:
在这里插入图片描述
fragment.startActivityForResult:
在这里插入图片描述
两种方式经过对比发现activity.startActivityForResult启动回调requestCode是正常的,activity.startActivityForResult启动回调requestCode的值是65537,在fragment中用activity启动的requestCode不是我们传的值,那么肯定是在启动的时候做了什么处理,我们在源码中可以找到答案:

androidx.fragment.app.Fragment

public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,
            int requestCode) {
        startActivityForResult(intent, requestCode, null);
}
public void startActivityForResult(@SuppressLint("UnknownNullness") 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);
}

androidx.fragment.app.FragmentHostCallback

public void onStartActivityFromFragment(
            @NonNull Fragment fragment, @SuppressLint("UnknownNullness") Intent intent,
            int requestCode, @Nullable Bundle options) {
        if (requestCode != -1) {
            throw new IllegalStateException(
                    "Starting activity with a requestCode requires a FragmentActivity host");
        }
        mContext.startActivity(intent);
    }

FragmentHostCallback是一个抽象方法,在FragmentActivity中创建了HostCallbacks并继承了FragmentHostCallback。

androidx.fragment.app.FragmentActivity

class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
        ViewModelStoreOwner,
        OnBackPressedDispatcherOwner {
        ...
         @Override
        public void onStartActivityFromFragment(@NonNull Fragment fragment, Intent intent,
                int requestCode) {
            FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode);
        }
        ...
}
public void startActivityFromFragment(@NonNull Fragment fragment,
            @SuppressLint("UnknownNullness") Intent intent, int requestCode) {
        startActivityFromFragment(fragment, intent, requestCode, null);
    }
public void startActivityFromFragment(@NonNull Fragment fragment,
            @SuppressLint("UnknownNullness") Intent intent, int requestCode,
            @Nullable Bundle options) {
        mStartedActivityFromFragment = true;
        try {
            if (requestCode == -1) {
                ActivityCompat.startActivityForResult(this, intent, -1, options);
                return;
            }
            checkForValidRequestCode(requestCode);
            int requestIndex = allocateRequestIndex(fragment);
            ActivityCompat.startActivityForResult(
                    this, intent, ((requestIndex + 1) << 16) + (requestCode & 0xffff), options);
        } finally {
            mStartedActivityFromFragment = false;
        }
    }

最终会调用FragmentActivity中的startActivityFromFragment方法,requestCode在这里发生了改变,由此可以知道fragment调用startActivityForResult时requestCode会发生改变,所以在Fragment中调用activity.startActivityForResult,不会回调onActivityResult方法。

结论

在fragmrnt中启动Activty调用fragment.startActivityForResult,否则不会回调onActivityResult方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值