Ответ 1
К сожалению, ActivityCompat.startActivityForResult()
работает не совсем правильно в Fragments
(см. ответ Алекс Локвуд). Несколько недель я удивлялся тому, как Google никогда не предоставлял нам метод ActivityCompat
, эквивалентный реализации фрагмента startActivityForResult()
. О чем они думали?! Но тогда у меня возникла идея: давайте взглянем на то, как метод действительно реализован.
На самом деле 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));
}
Google использует некоторое нечетное смещение байта в коде запроса, чтобы впоследствии вызывать только вызывающий фрагмент 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);
}
}
Скопируйте этот метод в любом месте и используйте его из вашего фрагмента. Его onActivityResult()
будет вызываться как следует.
UPDATE:
Была выпущена библиотека поддержки v23.2, и кажется, что startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)
выполняет эту работу:)