在 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位保存来自 Fragment 的 requestCode 值。
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 混淆。