Sergio B.
Sergio B.

Reputation: 990

Android FragmentManager and Fragment Result API

How can be that a fragment F which uses the new Fragment Result API to get results from 2 other fragments: A, B gets the result from A but not from B because B has a different parent FragmentManager (and I don't know why) ? How could be something like that ? 2 fragments called in the same way but they end up having same Activity but different FragmentManager ? The function calls are the following:

//THIS DOESN'T WORK. THE LISTENER IS NOT CALLED AFTER THE RESULT IS SET

private fun navigateToItemLocation() {

        setFragmentResultListener(REQUEST_LOCATION_KEY) { s: String, bundle: Bundle ->

            val locationId = bundle.getParcelable<ParcelUuid>(LOCATION_ID)!!.uuid
            viewModel.viewModelScope.launch(Dispatchers.IO) {
                val location = LocationRepository().get(locationId)!!
                changeItemLocation(location)
            }
        }


        val action = ItemRegistrationPagerHolderDirections.actionNavItemRegistrationPagerToNavStockLocationSelection()
        findNavController().navigate(action)
    }

//THIS WORKS FINE:

private fun navigateToItemDetails(item: Item2) {

        setFragmentResultListener(SELECTED_ITEM_KEY) { s: String, bundle: Bundle ->

            val propertySetId = bundle.getParcelable<ParcelUuid>(SELECTED_ITEM_SET_ID)!!.uuid
            clearFragmentResultListener(SELECTED_ITEM_KEY)

            viewModel.viewModelScope.launch(Dispatchers.IO) {
                val repository = PropertySetRepository()
                val propertySet = repository.get(propertySetId)!!
                val propertySetInfo = ItemFactory.loadPropertySetInfo(propertySet)

                withContext(Dispatchers.Main) { setPackageCode(null) }
                selectItem(item.item, propertySetInfo, item.description, null)
            }
        }

        val action = ItemRegistrationPagerHolderDirections.actionNavItemRegistrationToNavStockItemDetails(ParcelUuid(item.item.id), true)
        findNavController().navigate(action)
    }

Both fragments A and B are in a separate Dynamic Feature. The only single problem I have is that when the following function is called:

fun onSelect() {

        viewModel.pickedLocation.value = (viewModel.selectedLocation as? LocationExt2?)?.location
        val result = bundleOf(Pair(LOCATION_ID, ParcelUuid(viewModel.pickedLocation.value!!.id)))
        setFragmentResult(REQUEST_LOCATION_KEY, result)
        findNavController().popBackStack()
    }

setFragmentResult(REQUEST_LOCATION_KEY, result)

Doesn't produce any result because the FragmentManager is not the same of the calling Fragment. The same method in fragment A which is:

private fun onSetSelected(id: UUID) {

    propertySets.removeObservers(viewLifecycleOwner)
    adapter.tracker = null
    setFragmentResult(SELECTED_ITEM_KEY, bundleOf(Pair(SELECTED_ITEM_SET_ID, ParcelUuid(id))))
    findNavController().popBackStack()
}

As a temporarily workaround I replaced the call to Fragment's FragmentManager with Activity.supportFragmentManager.setFragmentResultListener. It works but still I do not understand why fragments A and B behave differently...

Upvotes: 3

Views: 4930

Answers (2)

BestPractice2Go
BestPractice2Go

Reputation: 305

Check this blog article for the principles and rules with Fragment Result API on medium: https://medium.com/@FrederickKlyk/state-of-the-art-communication-between-fragments-and-their-activity-daa1fe4e014d

Only one listener can be registered for a specific request key.

If more than one listener is registered on the same key, the previous one will be replaced by the newest listener.

Upvotes: 0

Edward Ablekimov
Edward Ablekimov

Reputation: 79

Check that fragment where you listen for fragment result and fragment where you set the result are in the same fragment manager.

Common case where this would happen is if you are using Activity.getSupportFragmentManager() or Fragment.getParentFragmentManager() alongside Fragment.getChildFragmentManager().

Upvotes: 4

Related Questions