Fragment打开页面

April 2, 2019

Fragment 内部调用自有方法 startActivityForResult()

1
2
3
public void startActivityForResult(Intent intent, int requestCode) {
    startActivityForResult(intent, requestCode, null);
}

该方法辗转调用同名重载方法,方法内调用名为 mHost 变量的方法,该变量的类型为 FragmentHostCallback

1
2
3
4
5
6
7
8
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
    // 如果Fragment没有绑定到Activity,即宿主实例不存在,会抛出异常
    if (mHost == null) {
        throw new IllegalStateException("Fragment " + this + " not attached to Activity");
    }
    // 调用方法
    mHost.onStartActivityFromFragment(this, intent, requestCode, options);
}

FragmentHostCallback 是抽象类,继承抽象父类 FragmentContainer,由 Fragment 所依附的宿主实现。

1
FragmentHostCallback mHost;

实现该抽象类表示具体实现类具有保存和展示Fragment的能力。

1
2
3
4
5
6
7
8
9
10
public abstract class FragmentHostCallback<E> extends FragmentContainer {
    public void onStartActivityFromFragment(
            Fragment fragment, 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。实现抽象类的同时还复写了父类的实现逻辑,当 Fragment 调用该方法时,实际调用 FragmentActivity 实现的成员方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class FragmentActivity extends BaseFragmentActivityApi16 implements
        ViewModelStoreOwner,
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator {
            
    .....
        
    // 面试考点:非静态内部类隐式持有外部类的实例引用
    class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
        .....

        @Override
        public void onStartActivityFromFragment(
                Fragment fragment, Intent intent, int requestCode, @Nullable Bundle options) {
            // 内部类调用了宿主的成员方法,相当于做了一层桥接
            FragmentActivity.this.startActivityFromFragment(fragment, intent, requestCode, options);
        }
    }
}

看宿主 FragmentActivity 的方法实现:方法内实参 requestCode 高16位保存 (requestIndex+1) 的值,低16位保存来自 FragmentrequestCode 值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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);
        // Activity给Fragment的请求生成requestIndex,用于后续匹配返回的Fragment
        int requestIndex = allocateRequestIndex(fragment);
        // requestIndex放在requestCode实参高16位,Fragment提供的requestCode放在实参低16位
        ActivityCompat.startActivityForResult(
                this, intent, ((requestIndex + 1) << 16) + (requestCode & 0xffff), options);
    } finally {
        mStartedActivityFromFragment = false;
    }
}

当结果从其他 Activity 回到 Fragment 所在宿主 Activity 时,宿主页面先检查 requestIndex 的值,判断原始请求是否来自 Fragment

requestCode 高16位非零表示该请求来自 Fragment,所以请求要转发给源 Fragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    mFragments.noteStateNotSaved();
    // 取出requestCode高16位
    int requestIndex = requestCode>>16;

    // requestIndex非0表示请求来自Fragment
    if (requestIndex != 0) {
        requestIndex--;

        // 用requestIndex找对应的请求Fragment名称
        String who = mPendingFragmentActivityResults.get(requestIndex);
        // 请求完成转发,可以移除该requestIndex的记录
        mPendingFragmentActivityResults.remove(requestIndex);
        if (who == null) {
            Log.w(TAG, "Activity result delivered for unknown Fragment.");
            return;
        }
        // 从Activity的Fragment栈查找接收数据的目标实例
        Fragment targetFragment = mFragments.findFragmentByWho(who);
        // 如果此时Fragment已被销毁,返回的结果直接丢弃
        if (targetFragment == null) {
            Log.w(TAG, "Activity result no fragment exists for who: " + who);
        } else {
            // 进行与操作后就是请求的原始requestCode,即低16位数据
            // 作为参数和返回结果调用Fragment.onActivityResult()
            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;
    }
  
    // 请求交给Activity执行
    super.onActivityResult(requestCode, resultCode, data);
}

由于上述调用位于 FragmentActivity 中,如果重写该方法时没调用 super.onActivityResult(int requestCode, int resultCode, Intent data),页面返回结果不会得到正确处理,对应 Fragment 也不会收到该结果通知。

可知,Activity 自己调用 onActivityResult 方法时传入的 requestCode 不能大于 0xFFFF,否则会和来自 Fragment 的请求 requestCode 混淆。