SoFunction
Updated on 2025-03-11

Solution to the problem of onActivityResult not being able to callback correctly when Fragment is nested in multiple layers in Android

Preface:

Fragment can also use the startActivityForResult method to open an Activity and then process the result in its onActivityResult method. However, when the Fragment is nested, the FragmentActivity bug will only call back the outermost Fragment's onActivityResult method, so the current Fragment cannot receive the result.

BUG analysis:

Before solving this problem, we will analyze the cause through the source code, and take the support-v4 library in version 22.2.1 as an example.

Let's start the analysis with Fragment's startActivityForResult

public void startActivityForResult(Intent intent, int requestCode) {
  if( == null) {
    throw new IllegalStateException("Fragment " + this + " not attached to Activity");
  } else {
    (this, intent, requestCode);
  }
}

It is obvious that the startActivityForFragment method of FragmentActivity is called directly

public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode) {
  if(requestCode == -1) {
    (intent, -1);
  } else if((requestCode & -65536) != 0) {
    throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
  } else {
    (intent, ( + 1 << 16) + (requestCode & '\uffff'));
  }
}

Here, the requestCode and the mIndex of the Fragment are fused into an integer as the new requestCode. Then the high 16 bits of the new requestCode represent the index of the Fragment, and the low 16 is the original requestCode. It seems that the mIndex of the Fragment is used as the basis for searching.

Next, let’s look at the onActivityResult method of FragmentActivity

protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  ();
  int index = requestCode >> 16;
  if(index != 0) {
    --index;
    if( != null && index >= 0 && index < ()) {
      Fragment frag = (Fragment)(index);
      if(frag == null) {
        ("FragmentActivity", "Activity result no fragment exists for index: 0x" + (requestCode));
      } else {
        (requestCode & '\uffff', resultCode, data);
      }

    } else {
      ("FragmentActivity", "Activity result fragment index out of range: 0x" + (requestCode));
    }
  } else {
    (requestCode, resultCode, data);
  }
}

Take out the high 16 bits of requestCode here, and the mIndex of the child Fragment is not equal to 0, but then directly find the Fragment from the Activity Fragment list according to the index. If your Fragment is managed by the childFragmentManager of the quilt Fragment, it will definitely not be found, so the answer is very clear.

Solve the problem:

There are two solutions to this problem

The first is to directly upgrade support-v4 to 23.2.0 or above, because this bug is fixed above 23.2.0. I won’t repeat how to solve it. Those who are interested can study it yourself. However, due to various reasons, there are still many people who cannot upgrade 23.2.0.

The second method is to do it yourself and rewrite the relevant methods in the Fragment layer to solve the problem

Next, we will introduce the method of making yourself rich and full of food and clothing, and the complete implementation is as follows:

public class ForResultNestedCompatFragment extends Fragment {
  private ForResultNestedCompatFragment forResultChildFragment;

  @Override
  public void startActivityForResult(Intent intent, int requestCode) {
    Fragment parentFragment = getParentFragment();
    if (parentFragment != null && parentFragment instanceof ForResultNestedCompatFragment) {
      ((ForResultNestedCompatFragment) parentFragment).startActivityForResultFromChildFragment(intent, requestCode, this);
    } else {
      forResultChildFragment = null;
      (intent, requestCode);
    }
  }

  private void startActivityForResultFromChildFragment(Intent intent, int requestCode, ForResultNestedCompatFragment childFragment) {
    forResultChildFragment = childFragment;

    Fragment parentFragment = getParentFragment();
    if (parentFragment != null && parentFragment instanceof ForResultNestedCompatFragment) {
      ((ForResultNestedCompatFragment) parentFragment).startActivityForResultFromChildFragment(intent, requestCode, this);
    } else {
      (intent, requestCode);
    }
  }

  @Override
  public final void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (forResultChildFragment != null) {
      (requestCode, resultCode, data);
      forResultChildFragment = null;
    } else {
      onActivityResultNestedCompat(requestCode, resultCode, data);
    }
  }

  public void onActivityResultNestedCompat(int requestCode, int resultCode, Intent data) {

  }
}

Specific ideasIn a word, when startingActivityForResult is, when startingActivityForResult is layer by layer, let the parent Fragment hold the reference to the child Fragment at night, and when calling onActivityResult, the parent Fragment is then passed to the child Fragment layer by layer.

Specific usageIt is to let all Fragments inherit the ForResultNestedCompatFragment, and then replace the onActivityResult method with the onActivityResultNestedCompat method.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.