遗憾的是,ActivityCompat.startActivityForResult()
在Fragments
中并不能正常工作(请参见Alex Lockwood的回答)。几周来我一直感叹Google从未给我们提供与Fragment实现的startActivityForResult()
等效的ActivityCompat
方法。他们在想什么?!但后来我有了一个想法:让我们看看这种方法实际上是如何实现的。
事实上,在Fragment
中的startActivityForResult()
与Activity
中的不同(请参见这里):
public void startActivityForResult(Intent intent, int requestCode) {
if (mActivity == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mActivity.startActivityFromFragment(this, intent, requestCode);
}
现在,startActivityFromFragment()
的代码看起来像这样(请参阅此处):
public void startActivityFromFragment(Fragment fragment, Intent intent,
int requestCode) {
if (requestCode == -1) {
super.startActivityForResult(intent, -1);
return;
}
if ((requestCode&0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
super.startActivityForResult(intent,
((fragment.mIndex + 1) << 16) + (requestCode & 0xffff));
}
谷歌对请求代码进行了一些奇怪的字节移位,以确保仅在调用片段之后调用 onActivityResult()
。现在,由于ActivityCompat
没有提供任何 startActivityFromFragment()
,唯一的选择是自己实现它。反射需要访问包私有字段mIndex
。
public static void startActivityForResult(Fragment fragment, Intent intent,
int requestCode, Bundle options) {
if (Build.VERSION.SDK_INT >= 16) {
if ((requestCode & 0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits" +
" for requestCode");
}
if (requestCode != -1) {
try {
Field mIndex = Fragment.class.getDeclaredField("mIndex");
mIndex.setAccessible(true);
requestCode = ((mIndex.getInt(this) + 1) << 16) + (requestCode & 0xffff);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
ActivityCompat.startActivityForResult(fragment.getActivity(), intent,
requestCode, options);
} else {
fragment.getActivity().startActivityFromFragment(this, intent, requestCode);
}
}
您可以随意复制该方法并在 Fragment 中使用它。它的onActivityResult()
将按预期被调用。
更新:
支持库 v23.2 已经发布,现在startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)
可以胜任这项工作:)