Home > Software engineering >  Return data when a screen is closed
Return data when a screen is closed

Time:10-14

I have several sub-screens which give the user the option to save some data. When that screen is closed, I want the parent screen, which pushed the sub-screen, to know whether data was saved or not. The sub-screens maintain a didSave flag and is set to true when data is saved.

There are several ways for the sub-screens to be closed:

  • hardware/software back button.
  • The close button on the AppBar.
  • A button on the screen itself.

I can handle the 3rd case using Navigator.pop(context, didSave) and in the parent that didSave flag is captured using final didSave = await Navigator.push<bool>(context, myRoute).

However, for the first 2 cases, the result will obviously be null.

I have looked into WillPopScope but that only is used to determine whether the screen should be closed or not. It doesn't seem that I can set any data to be returned for the push call.

I have also looked into wrapping the parent screen in a Provider where it can listen to didSave states but that will trigger immediately when emitted which is not desirable for my use case. I only want to act when the sub-screen is closed not when data is saved.

I can potentially use WillPopScope and emit an event there if a save operation has occured but I would like a simpler solution if available.

Is there a way for this that I am missing?

Thanks!

CodePudding user response:

Did you try to create the variable with state management? And there is method with the push that do task after user come from the child screen. So, when they come you can checkout the use have saved data or not.

For EG:

saved = false; //State management variable

//We are pushing on another screen.
Navigator.of(context).push(
                      MaterialPageRoute(
                        builder: (BuildContext context) =>
                            new ScreenName(),
                      ),
                    ).then((val) {
//This part with work when user popped the screen on which we have pushed
                      if (!saved) {//Do Something when not saved}
                    });

Try above code and let me know if you get any error or you're facing any issue.

CodePudding user response:

when you push a new route, using StatefulWidget, it will have a lifecycle starting from an createState, when the widget isn't there on the widget tree ( when we pop ), the dispose method will be called.

those cases of popping the route:

  • hardware/software back button.
  • The close button on the AppBar.
  • A button on the screen itself.

will trigger the dispose method to execute. so you can put inside it your logic that you want.

exmaple :

class classTest {
  bool didSave = false;
}

then when on the property where you want to push the screen set it to that classTest's didSave, as an example:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const YourRouteWidget(didSave: classTest.didSave,
  ),
  ),
);

on that point it's false, then when the user will complete using the screen, going back with any king of popping the route (with Navigator.pop(context), or with back button...), the dispose method will be called, so you can :

   void dispose() {
   if(/* your conditions*/ ) {
   classTest.didSave = true;
   }
    super.dispose();
  }

it will be back with a true value to the parent page.

CodePudding user response:

as you said the Provider will listen to didSave and this doesn't fit in your case you can use just a simple inheritedWidget:

wrapping the parent like this:

InheritedExampleWidget(
didSave: false,
child: Parent(),
),

you need to set a setter to didSave then on the ascendant widgets on the widget tree, you can:

InheritedExampleWidget.of(context).didSave = true;

this will not trigger it immediately, which the Provider package solves. then you can manage the state however you want

  • Related