How to handle fragment result callbacks in Kotlin Android
How to handle fragment result callbacks in Kotlin Android.
In Android development, fragments are reusable UI components that can be combined to create flexible and responsive user interfaces. One common scenario when working with fragments is the need to communicate between fragments and their parent activities. Fragment result callbacks provide a convenient way to achieve this communication.
In this tutorial, we will explore how to handle fragment result callbacks in Kotlin Android. We will cover the following topics:
- Overview of Fragment Result Callbacks
- Implementing Fragment Result Callbacks
- Sending Results from Fragments
- Receiving Results in Activities
- Handling Multiple Fragments with Result Callbacks
1. Overview of Fragment Result Callbacks
Fragment result callbacks are a mechanism introduced in AndroidX to simplify the communication between fragments and their parent activities. With fragment result callbacks, a fragment can send a result to its parent activity, and the activity can handle the result in a callback method.
2. Implementing Fragment Result Callbacks
To implement fragment result callbacks, you need to follow these steps:
Step 1: Add the necessary dependencies
First, make sure you have the necessary dependencies in your project. In your app-level build.gradle
file, add the following dependencies:
implementation 'androidx.fragment:fragment-ktx:1.3.6'
Step 2: Define a contract for the result
Next, define a contract for the result communication between the fragment and the activity. This contract should specify the result code and any data associated with the result.
object MyResultContract : ActivityResultContract<Bundle?, Bundle?>() {
override fun createIntent(context: Context, input: Bundle?): Intent {
// Create an intent to launch the activity that will handle the result
return Intent(context, MyResultHandlingActivity::class.java)
.putExtra("input_data", input)
}
override fun parseResult(resultCode: Int, intent: Intent?): Bundle? {
// Parse the result data from the intent
return intent?.getBundleExtra("output_data")
}
}
Step 3: Implement the callback in the activity
In the parent activity, implement the ActivityResultRegistry
interface and override the onActivityResult
method to handle the result.
class MyActivity : AppCompatActivity(), ActivityResultRegistryOwner {
private val resultRegistry = ActivityResultRegistry()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Register the result contract with the activity result registry
val resultContract = MyResultContract()
val resultLauncher = resultRegistry.register("my_result", resultContract) { result ->
// Handle the result here
handleResult(result)
}
// Start the fragment that will send the result
val fragment = MyFragment()
fragment.registerForActivityResult(resultContract, resultLauncher)
supportFragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit()
}
private fun handleResult(result: Bundle?) {
// Handle the result here
}
override fun getActivityResultRegistry(): ActivityResultRegistry {
return resultRegistry
}
}
Step 4: Send the result from the fragment
In the fragment, use the ActivityResultLauncher
to send the result back to the activity.
class MyFragment : Fragment() {
private lateinit var resultLauncher: ActivityResultLauncher<Bundle?>
override fun onAttach(context: Context) {
super.onAttach(context)
// Get the result launcher from the activity
val activity = requireActivity() as MyActivity
resultLauncher = activity.resultRegistry.get("my_result")
}
private fun sendResult() {
val resultData = Bundle().apply {
// Put the result data here
}
resultLauncher.launch(resultData)
}
}
3. Sending Results from Fragments
To send a result from a fragment to its parent activity, follow these steps:
- Create an instance of the result data, if any.
- Use the
ActivityResultLauncher
to launch the result with the result data.
private fun sendResult() {
val resultData = Bundle().apply {
// Put the result data here
}
resultLauncher.launch(resultData)
}
4. Receiving Results in Activities
To receive a result in the parent activity, follow these steps:
- Implement the
ActivityResultRegistryOwner
interface in the activity. - Override the
getActivityResultRegistry
method to return theActivityResultRegistry
instance. - Register the result contract with the activity result registry.
- Handle the result in the callback method.
class MyActivity : AppCompatActivity(), ActivityResultRegistryOwner {
private val resultRegistry = ActivityResultRegistry()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Register the result contract with the activity result registry
val resultContract = MyResultContract()
val resultLauncher = resultRegistry.register("my_result", resultContract) { result ->
// Handle the result here
handleResult(result)
}
// Start the fragment that will send the result
val fragment = MyFragment()
fragment.registerForActivityResult(resultContract, resultLauncher)
supportFragmentManager.beginTransaction()
.replace(R.id.container, fragment)
.commit()
}
private fun handleResult(result: Bundle?) {
// Handle the result here
}
override fun getActivityResultRegistry(): ActivityResultRegistry {
return resultRegistry
}
}
5. Handling Multiple Fragments with Result Callbacks
If you have multiple fragments that need to send results to the parent activity, you can use different result contracts for each fragment. Simply define multiple result contracts and register them with the activity result registry.
class MyActivity : AppCompatActivity(), ActivityResultRegistryOwner {
private val resultRegistry = ActivityResultRegistry()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Register the result contracts with the activity result registry
val resultContract1 = MyResultContract1()
val resultContract2 = MyResultContract2()
val resultLauncher1 = resultRegistry.register("my_result1", resultContract1) { result ->
// Handle the result from fragment 1
handleResult1(result)
}
val resultLauncher2 = resultRegistry.register("my_result2", resultContract2) { result ->
// Handle the result from fragment 2
handleResult2(result)
}
// Start the fragments that will send the results
val fragment1 = MyFragment1()
fragment1.registerForActivityResult(resultContract1, resultLauncher1)
val fragment2 = MyFragment2()
fragment2.registerForActivityResult(resultContract2, resultLauncher2)
supportFragmentManager.beginTransaction()
.replace(R.id.container1, fragment1)
.replace(R.id.container2, fragment2)
.commit()
}
private fun handleResult1(result: Bundle?) {
// Handle the result from fragment 1
}
private fun handleResult2(result: Bundle?) {
// Handle the result from fragment 2
}
override fun getActivityResultRegistry(): ActivityResultRegistry {
return resultRegistry
}
}
That's it! You have now learned how to handle fragment result callbacks in Kotlin Android. By following these steps, you can easily communicate between fragments and their parent activities using result callbacks.