question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal for Fragment Results API

See original GitHub issue

Problem

We are currently using our own solution for handling fragment to fragment communication, since there was no official way to do that, that fits our architecture last time we checked (#2219 ). While this approach works, it comes with couple of caveats.

Screen results are not lifecycle aware

We dispatch the screen results after the fragment transactions are finished. Since the callback is not lifecycle aware, it’s possible for the app to access views when they are not inflated or in backgroud which can cause crashes to the app.

Bugs

We currently have a open bug report for screen results, where sometimes the screen results are being casted to a different type and cause the app to crash. While it’s easy to just check the type before casting, it shouldn’t have happened in the first place.

When passing back the screen result, we try to make sure the target fragment is present. Sometimes that causes the app to crash when the fragment has not been attached to the activity or if the app has gone into background in the process.

Extending a new type when creating Fragment

Since Fragment didn’t had concept of screen results, we created a new type ExpectsResult to implement onScreenResult callback which receives the screen results. Accidentally missing extending this type can cause the app to crash.

Goal

The goal is to avoid managing our own solution for manging communication between fragments, and to resolve the above mentioned issues.

Approach

Android has created a Fragment results API which is available from version 1.3.0-alpha04, which allows us to pass data between fragments. It solves some of the concerns we mentioned above, the results listener is lifecycle aware and only passes the results when the fragment is in started state.

The results listener API is baked into FragmentManager, which allows us to directly use it in fragments without having to extend new types.

Listening to screen results

Fragment results API provides us with a lifecycle aware observer that let’s us listen to results based on the request key

setFragmentResultListener(DatePickerResult) { result ->
  if (result is Succeeded) {
    val selectedDate = result.result as SelectedDate
    val event = ManualDateSelected(selectedDate = selectedDate.date, currentDate = LocalDate.now(userClock))
    hotEvents.onNext(event)
  }
}

For listening to multiple fragment results, we can simply add another listener with a different request key

setFragmentResultListener(DatePickerResult) { result ->
  if (result is Succeeded) {
    val selectedDate = result.result as SelectedDate
    val event = ManualDateSelected(selectedDate = selectedDate.date, currentDate = LocalDate.now(userClock))
    hotEvents.onNext(event)
  }
}

setFragmentResultListener(OverdueAppointmentRemoved) {
  router.pop()
}

Sending the result

We can continue using the existing Router API for sending back the results, internal Router will send the result using FragmentManager which acts as a central store for all the fragment results.

router.popWithResult(Succeeded(SelectedDate(setDate)))

Migration

The migration process for new fragment results API is pretty straightforward.

  1. In onViewCreated of the fragment, we need to add a listener for the fragment results for the request key. If you have multiple request keys, you need to add multiple listeners. (We can use method references for result handling)

image

  1. Once you have added all the listeners for the request keys in the existing onScreenResult, we can stop extending ExpectsResult and remove onScreenResult

Consequences

Multiple listeners

Traditionally when we are handling screen results, we just have one single call back and that would return all the results. But with this approach we have to add multiple listeners to handle different requests.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:12 (12 by maintainers)

github_iconTop GitHub Comments

2reactions
msasikanthcommented, Aug 5, 2021

Q: With dispatchScreenResult, we’d still have to implement the onScreenResult ToDo the body, right?

Yep, it will pass the request type and result and we can continue using the existing approach. So, only the internal implementation is changed.

2reactions
msasikanthcommented, Aug 5, 2021

The listeners are lifecycle aware, so internally it will observe lifecycle and do necessary operations. So we will only get results when the state is started

image

I have also updated the code to be a bit more concise and readable.

image

Read more comments on GitHub >

github_iconTop Results From Across the Web

[Proposal] Fragments - APIs
An implementation of fragments exist as DocumentFragment but these share a weak reference with their children, resulting in the Node loosing its children...
Read more >
The right way to get a result. Part 2. Fragment Result API
The first part was about data transfer between Activities via the new Activity Result Api. This time, we'll cover the Fragment-based solution ...
Read more >
Sample for my Fragment Result API article
Sample for my Fragment Result API article. Contribute to BelyakovLeonid/FragmentResultSample development by creating an account on GitHub.
Read more >
API Fragments - simple flexibility
Pre-made. Defining API interfaces based on specific consumer needs - simple for each consumer, but not necessarily reusable. · Deli-style.
Read more >
Taming the Fragment Result API
Introducing an interface in the activity that can receive the result from a fragment is the oldest but the safest way. But again,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found