Understand the behavior of startActivityForResult for Fragment and Activity

The basic startActivityForResult Activity flow

The entire startActivityForResult and onActivityResult is allowed a 2-way communication between the source activity and the destination activity. Its flow is as shown in the diagram below.

From the below flow, We can easily understand the flow of OnActivityResult from Source Activity to Destination Activity

The source activity call, startActivityForResult by sending in the intent together with the request code to Android SDK.

Android SDK then opens the activity accordingly as stated in the Intent.
Once the destination activity has finished with its job, it returns to its caller activity.

It could send the result back using setResult by sending in the resultCode and intent

Several notes here:

The resultCode is used by the destination activity to flag to its source activity what it's the status (e.g. OK, Cancel, etc).

The request code is used by the source activity to know which destination activity is returning the call.

We could see that the destination activity has no visibility of the request code.

Undocumented startActivityForResult Fragment Flow

In Fragment, we also have startActivityForResult function to call, and also onActivityResult function to override.

This raises several questions…e.g. How does it works? Is it the same as the activity’s startActivityForResult and onActivityResult? How are they related?
The short answer is, they are similar but subtly different. A frequent cause of confusion, and bug. So it’s important to understand the similarity and differences.

The fragment flow illustrated.

Below is the diagram the illustrates clearly how it all works together. The differences with activity’s startActivityForResult and onActivityResult flow are colored in RED.

Let’s more elaborate on it.

When we call Fragment’s startActivityForResult (note: NOT activity?.startActivityForResult), the creation of destination activity is the same. However, the difference is the onActivityResult.

startActivityForResult() must handle it from the fragment's onActivityForResult()

getActivity().startActivityForResult() must handle it from the activity's onActivityForResult()

If you’re on a fragment and you want to handle the result on the fragment, use onActivityForResult(), otherwise, if you want to handle it from the activity of the fragment, use getActivity.startActivityForResult()

When Android SDK returns onActivityResult, the request code has been altered. A 0xP0000 is appended to the original requestCode.

The P-value start from 1, and incremented for each onActivityResult is called from the same destination fragment. (If another destination Fragment is called, the P-value is reset).

e.g. if the original requestCode is 0xFF (i.e. 255), the requestCode return the first time will be 0x100FF. The second time return requestCode will be 0x200FF.

Upon returning to the source activity’s onActivityResult, it is expected that it should call super.onActivityResult, which resides in FragmentActivity (the parent of AppCompatActivity)

The onActivityResult in FragmentActivity will then extract the P value (using requestCode >> 16). The P is the index of the array where the source fragment is stored. (e.g. if requestCode is 0x200FF, then 0x200FF >> 16 = 2)

Using the P-value, it now has access to the source fragment, which is used in step 9 below.

Now, it strip away the P value from the requestCode (using requestCode & 0xffff), to get back to the original request code (e.g. if requestCode is 0x200FF, then 0x200FF & 0xffff = 0xFF)

As now it gets the original request code that the source fragment created, it could call the source fragment’s onActivityResult with the original request code.

Some basic points which want to know.

A. The behavior of Activity’s startActivityForResult is different from Fragment’s startActivityForResult

In Fragment, if we call activity?.startActivityForResult(...), Then Fragment’s onActivityResult will not be called automatically.

B. If we override activity’s onActivityResult, make sure we have super.onActivityResult in place

If we override source activity’s onActivityResult, but forget to have super.onActivityResult then Fragment’s onActivityResult will not be called.

C. The requestCode seen in activity’s onActivityResult is different from the one fragment provided

Due to the reason, Android SDK appended P to the requestCode, in the activity’s onActivityResult, we’ll never get the identical requestCode there. This at times causes confusion to the developer when debugging the code there.

D. When an activity is restored from the state (i.e. onStateInstance != null), it should avoid recreate its fragment.

When onActivityResult is called, it tried to retrieve the original fragment. This is also performed for the activity that is restored from a killed state (e.g. emulated using Don’t Keep Activity).

So if the developer recreate the Fragment every time onCreate is called (regardless if it is a restored state or not), then the original Fragment that was restored will be destroyed, and onActivityResult of the caller, the fragment will mysteriously not be called.

This is a pitfall even for many experienced developers and app released in the field, as it is very hard to an identified bug (since it is not happening every time, and require a more complex flow to trigger).

Thanks for reading…

--

--

--

Senior Software Engineer | Android | Java | Kotlin|Xamarin Native Android|Flutter

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

How to Add Bottom Navigation in Jetpack Compose?

Optimize, shrink and obfuscate your android app

Understanding MVVM pattern for Android in 2021

Understanding XML Files in Android

Hilt — An optimal dependency injector for Android Projects.

View Binding vs Data Binding Gotchas

How to Implement Hilt in Android App?

How to create Repair Powerup

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Abhishek Srivastava

Abhishek Srivastava

Senior Software Engineer | Android | Java | Kotlin|Xamarin Native Android|Flutter

More from Medium

Their eyes met, and lips smiled,

The Imperfection of Perfection

Fifty Sense: 50 Things I Learned By 50

Https://www.fortheloveofcrypto.org