话说Fragment,每一个做过安卓开发的同学肯定都熟悉,但是如果我要问在接收返回值时,如果Fragment和Activity具有相同的请求码requestCode,他们是怎么区分的呢。
要知道这个问题,那么我们就必须要深入源码了。其实Fragment也有相应的方法:
public void startActivityForResult(Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
我们也可以在Fragment中重写onActivityResult方法:
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
现在你是不是已经有点困惑了,如果我们在Activity中也重写onActivityResult方法,返回的结果到底是谁处理的呢?
在Fragment中有两种方式:
startActivityForResult(new Intent(mActivity, FourActivity.class),2);
mActivity.startActivityForResult(new Intent(mActivity, FourActivity.class),2);
重点来了,其实最主要的区别就在这里,当我们在Fragment中通过第一种方式调用时,调用到了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;
}
}
看到了吧,你的requestCode已经被转化了,如果你通过第二种方式调用的话,请求码是不会被转化的,所以,就算你在Fragment和Activity中有相同的请求码,实际上也是不同的。那我们在看看返回结果的处理:
@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);
}
当我们重写FragmentActivity的onActivityResult的时候,一定要记得调用:
super.onActivityResult(requestCode, resultCode, data);
因为返回结果必然是先让Activity接收到的,然后在super中判断请求码来自哪里。系统对于Fragment和FragmentActivity的requestCode做了处理,Fragment的处理成高16位的值,FragmentActivity的是你给的值,可能你会说,那我在FragmentActivity中的请求码是高16位的值怎么办,比如是Integer.MAX_VALUE,哈哈,我想说,你敢给,系统就敢给你抛个异常,不信请看FragmentActivity的startActivityForResult方法:
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);
}
static void checkForValidRequestCode(int requestCode) {
if ((requestCode & 0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");//看这里
}
}
如果你不想要异常,你还是乖一点吧。
总结,如果你想在Fragment中处理结果就直接使用startActivityForResult方法,不要用FragmentActivity的,我们也不用担心请求码相同造成什么问题,但是一定要记住,如果你重写了FragmentActivity的onActivityResult方法时,一定要调用super的onActivityResult方法,不然你的fragment是接收不到结果的,当然如果你不嫌麻烦,自己去回调给Fragment的onActivityResult方法也行,但是系统已经实现了,我们何必多此一举呢。