Sadly, ActivityCompat.startActivityForResult()
doesn't work quite right in Fragments
(see Alex Lockwood's answer). For several weeks I marvelled at how Google never gave us an ActivityCompat
method equivalent to Fragment's implementation of startActivityForResult()
. What were they thinking?! But then I had an idea: Let's take a look at how the method is actually implemented.
As a matter of fact, startActivityForResult()
in Fragment is different from the one in Activity (see here):
public void startActivityForResult(Intent intent, int requestCode) {
if (mActivity == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mActivity.startActivityFromFragment(this, intent, requestCode);
}
Now startActivityFromFragment()
looks like this (see here):
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 uses some odd byte shifting on the request code to make sure only the calling Fragment's onActivityResult()
is called afterwards. Now since ActivityCompat
doesn't provide any startActivityFromFragment()
, the only option left is to implement it yourself. Reflection is required to access the package private field 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);
}
}
Copy that method anywhere you like and use it from your Fragment. Its onActivityResult()
will be called as it should.
UPDATE:
Support library v23.2 was released and it seems startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)
does the job now :)