I have a problem I can't solve. I have two fragments, one called "NotificationListFragment" that can navigate to a second fragment called "InfoNotificationFragment". Before calling the second fragment, I pass two parameters through the Bundle object:
- A closure of type "() -> Unit" that needs to be executed when the second fragment is closed;
- An object of type "MessageNotificationCompatible". Both are passed as Parcelable objects. The closure is set inside a class called "TrackedReference", which contains a map of objects of type "WeakReference", in order to avoid implementing marshalling.
Let me show you how this is done in the "NotificationListFragment" class:
adapter.action.observe(viewLifecycleOwner) { action ->
when(action) {
is NotificationAction.SelectionAction -> {
val message = action.infoNotification.toNotificationMessage()
val handler: () -> Unit = {
markInfoNotificationAsReadInRV(message.data.getID())
findNavController().navigateUp()
}
val closeHandler : CloseHandlerCompatible = CloseHandler(handler)
val b = Bundle()
b.putParcelable(InfoNotificationFragment.MESSAGE_KEY, message)
b.putParcelable(InfoNotificationFragment.CLOSURE_KEY, TrackedReference(closeHandler))
findNavController().navigate(R.id.action_notificationListFragment_to_infoNotificationFragment, b)
}
}
}
Inside the "InfoNotificationFragment" class, within the "onCreate()" method, the parameters passed through the Bundle are retrieved:
arguments?.let { bundle->
val closure : TrackedReference<*>
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
message = bundle.getParcelable(MESSAGE_KEY, NotificationMessageCompatible::class.java)
closure = bundle.getParcelable(CLOSURE_KEY, TrackedReference::class.java) as TrackedReference<*>
} else {
@Suppress("DEPRECATION")
message = bundle.getParcelable(MESSAGE_KEY)
@Suppress("DEPRECATION")
closure = (bundle.getParcelable(CLOSURE_KEY) as? TrackedReference<*>)!!
}
closeHandler = (closure.get as CloseHandlerCompatible).closeHandler
closure.removeStrongReference()
}
This second fragment has a button that, when clicked, calls the closure that was passed to it as a parameter:
binding.closeButton.setOnClickListener {
// Need for smart cast
val message = message ?: return@setOnClickListener
// I mark the notification it as read in memory
viewModel.markInfoNotificationAsRead(message.data.getID())
// I call the closeHandler method
this.closeHandler()
}
The problem I'm encountering is the following: everything works correctly following the standard flow. However, when the app remains in the background for a long time, and the activity and fragment view are recreated, I can no longer call the "findNavController().navigateUp()" method inside the closure.
Since the problem occurs at an unspecified time, I tried to simulate the same situation by attempting to activate the screen orientation (which is disabled by default for this activity).
Actually, by rotating the screen, I find myself in the same situation as when the app is in the background, so I can simulate this problem. In any case, the exception that I get when I try to call the "findNavController().navigateUp()" method after rotating the screen is the following:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: it.zucchetti.fq.qid, PID: 29563
java.lang.IllegalStateException: Fragment NotificationListFragment{846f563} (fc633911-2609-4220-8236-acfda3b0a01b) not associated with a fragment manager.
at androidx.fragment.app.Fragment.getParentFragmentManager(Fragment.java:1107)
at androidx.navigation.fragment.NavHostFragment$Companion.findNavController(NavHostFragment.kt:375)
at androidx.navigation.fragment.FragmentKt.findNavController(Fragment.kt:29)
at it.zucchetti.qauthenticator.ui.notificationlist.NotificationListFragment$onSuccess$1$handler$1.invoke(NotificationListFragment.kt:158)
at it.zucchetti.qauthenticator.ui.notificationlist.NotificationListFragment$onSuccess$1$handler$1.invoke(NotificationListFragment.kt:155)
at it.zucchetti.qauthenticator.ui.notification.info.InfoNotificationFragment.bindData$lambda$1(InfoNotificationFragment.kt:110)
at it.zucchetti.qauthenticator.ui.notification.info.InfoNotificationFragment.$r8$lambda$Trhe-1LjjI1Cfn283v0VQLwE1u0(Unknown Source:0)
at it.zucchetti.qauthenticator.ui.notification.info.InfoNotificationFragment$$ExternalSyntheticLambda0.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7792)
at android.widget.TextView.performClick(TextView.java:16112)
at android.view.View.performClickInternal(View.java:7769)
at android.view.View.access$3800(View.java:910)
at android.view.View$PerformClick.run(View.java:30218)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
at android.os.Looper.loop(Looper.java:313)
at android.app.ActivityThread.main(ActivityThread.java:8663)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
Could you tell me how to solve the problem?
I tried to change the way to go back to the previous fragment, to save the fragment's state, to save the NavHostFragment's state, but I still haven't solved the problem.