Fragment的状态保存startActivityForResult是哪个类的方法,在什么情况下使用?


Fragment调用startActivityForResult ---> HostCallbacks . onStartActivityFromFragment ---> FragmentActivity . startActivityFromFragment 

FragmentActivity的startActivityFromFragment方法

    public void startActivityFromFragment(Fragment fragment, 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父类BaseFragmentActivityJB 的 mStartedActivityFromFragment 设置为 true;
然后根据requestCode的值判断,调用startActivity默认这里的requestCode 为 -1 ,如果调用startActivityForResult则不会走这步;
下一步通过checkForValidRequestCode会查验requestCode是否正确

    static void checkForValidRequestCode(int requestCode) {
        if ((requestCode & 0xffff0000) != 0) {
            throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
        }
    }

如果指定的requestCode大于65535,则会报异常.

下一步调用allocateRequestIndex方法得到请求队列中的索引

 // Allocates the next available startActivityForResult request index.
    private int allocateRequestIndex(Fragment fragment) {
        // Sanity check that we havn't exhaused the request index space.
        if (mPendingFragmentActivityResults.size() >= MAX_NUM_PENDING_FRAGMENT_ACTIVITY_RESULTS) {
            throw new IllegalStateException("Too many pending Fragment activity results.");
        }

        // Find an unallocated request index in the mPendingFragmentActivityResults map.
        while (mPendingFragmentActivityResults.indexOfKey(mNextCandidateRequestIndex) >= 0) {
            mNextCandidateRequestIndex =
                    (mNextCandidateRequestIndex + 1) % MAX_NUM_PENDING_FRAGMENT_ACTIVITY_RESULTS;
        }

        int requestIndex = mNextCandidateRequestIndex;
        mPendingFragmentActivityResults.put(requestIndex, fragment.mWho);
        mNextCandidateRequestIndex =
                (mNextCandidateRequestIndex + 1) % MAX_NUM_PENDING_FRAGMENT_ACTIVITY_RESULTS;

        return requestIndex;
    }

如果队列中超过了65535-1  那么报参数错误,然后得到在等待获取结果的队列中的索引,indexOfKey >=0 代表已经存在了,只能将mNextCandidateRequestIndex+1;不存在则赋值给requestIndex 然后返回,并且将mNextCandidateRequestIndex+1 给下一个请求做准备.

下一步调用
ActivityCompat . startIntentSenderForResult(this, intent,((requestIndex + 1) << 16) + (requestCode & 0xffff), fillInIntent,flagsMask, flagsValues, extraFlags, options);
(requestIndex + 1) << 16  代表将请求的索引值左移16位,在较高16位中保存当前的索引值
requestCode & 0xffff  就是requestCode,为了屏蔽二进制位,置位0

    public static void startIntentSenderForResult(Activity activity, IntentSender intent,
            int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
            int extraFlags, @Nullable Bundle options) throws IntentSender.SendIntentException {
        if (Build.VERSION.SDK_INT >= 16) {
            ActivityCompatJB.startIntentSenderForResult(activity, intent, requestCode, fillInIntent,
                    flagsMask, flagsValues, extraFlags, options);
        } else {
            activity.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask,
                    flagsValues, extraFlags);
        }
    }

因此这里调用startIntentSenderForResult方法的参数requestCode实际上是 ((requestIndex + 1) << 16)  + (requestCode & 0xffff )  而不是之前的requestCode。
 

接着调用ActivityCompatJB . startIntentSenderForResult方法(这里只拿API>=16举例)

    public static void startIntentSenderForResult(Activity activity, IntentSender intent,
            int requestCode, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
            Bundle options) throws IntentSender.SendIntentException {
        activity.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask,
                flagsValues, extraFlags, options);
    }

最后调用Activity的 startIntentSenderForResult 方法,ActivityManagerNative.getDefault().startActivityIntentSender 真正启动一个Activity。

然后我们查看FragmentActivity中接收setResult的值的方法onActivityResult

 /**
     * Dispatch incoming result to the correct fragment.
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, 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;
        }

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

首先将requestCode值右移16位,得到他在等待处理Fragment数据队列的索引,由上面的 ActivityCompat . startIntentSenderForResult方法参数得知,requestCode是左移了16位,
那么这里就可以根据requestIndex的值判断是Fragment调用了startActivityForResult还是Activity,如果requestIndex不为0代表是Fragment触发,下面得到 targetFragment 然后可以通过targetFragment的onActivityResult方法得到返回值;如果requestIndex为0代表是Activity调用了startActivityForResult,那么直接返回的是Activity的onActivityResult方法。

 

需要注意:
Fragment 和 Activity 都有startActivityForResult方法,切记不要调用错误。如果发现Fragment 的onActivityResult拿不到数据,
而FragmentActivity拿到了数据,并且requestCode与Fragment中用到的requestCode不一致,那么一定是在Fragment中调用了FragmentActivity的startActivityForResult方法。
源码就可以看出requestCode不一致的原因了,使用Fragment发起的请求,因为一个Activity可以包含多个Fragment,而且都可以发起请求,那么会使用一个容器来保存发起请求的Fragment和它对应的requestCode,mPendingFragmentActivityResults就是这个容器,发起请求的时候将在容器中的index和requestCode算在一起,作为最终的requestCode。
FragmentActivity 和 它的内部类 HostCallbacks 分别展现了两个startActivityForResult方法的调用。FragmentActi本身是有startActivityForResult方法,依附它的Fragment也有startActivityForResult方法,那么放在HostCallbacks里,这就体现了HostCallbacks是一座桥梁,链接了Fragment和FragmentActivity之间的通信。

 

你可能感兴趣的:(Android源码)