Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get.back() doesn't work from an async function #47

Closed
dayofbrian opened this issue Apr 21, 2020 · 7 comments
Closed

Get.back() doesn't work from an async function #47

dayofbrian opened this issue Apr 21, 2020 · 7 comments
Assignees

Comments

@dayofbrian
Copy link

I have a page that will perform a HTTP Post when a button is pressed. That button will call an async function to perform the actual HTTP Post which could take a second or two. When I get a success or failure back I'm attempting to navigate back to the previous page, but it doesn't do anything.

No error was reported, it just fails silently.

I found a work around, just call the Get.back() function inside the button event:
onPressed: () {saveClicked(); Get.back();},

Flutter Version:
Flutter 1.12.13+hotfix.9 • channel stable • https://github.com/flutter/flutter.git
Framework • revision f139b11009 (3 weeks ago) • 2020-03-30 13:57:30 -0700
Engine • revision af51afceb8
Tools • Dart 2.7.2

Get Version:
get: ^1.17.2

Describe on which device you found the bug:
Samsung Galaxy S8

@jonataslaw
Copy link
Owner

I have a page that will perform a HTTP Post when a button is pressed. That button will call an async function to perform the actual HTTP Post which could take a second or two. When I get a success or failure back I'm attempting to navigate back to the previous page, but it doesn't do anything.

No error was reported, it just fails silently.

I found a work around, just call the Get.back() function inside the button event:
onPressed: () {saveClicked(); Get.back();},

Flutter Version:
Flutter 1.12.13+hotfix.9 • channel stable • https://github.com/flutter/flutter.git
Framework • revision f139b11009 (3 weeks ago) • 2020-03-30 13:57:30 -0700
Engine • revision af51afceb8
Tools • Dart 2.7.2

Get Version:
get: ^1.17.2

Describe on which device you found the bug:
Samsung Galaxy S8

Can you provide a Mock of the problem reproduction code? I have 3 applications in production that after the http request is sent, the app returns to the home page, and everything is working normally.
I believe that this is not related to the asynchronous function, but Get.back() should be in a place where it is never called.

Before providing your code (you can hide the API address), just test this:
onPressed: async () {saveClicked(); Get.back();},

If everything works normally, it means that there are no problems with asynchronous operations, but Get is not being called by your code.

Put a:

print("before get");
Get.back();
print("after get");

And you will know exactly what is going on. If the first print is not called, it is because your code is not even entering there.

@dayofbrian
Copy link
Author

It was certainly being called, I had a break point on the Get.back() command and it was being hit.

I tried modifying the onPressed: to be async like you mentioned and Get.back() worked.
I did some more debugging and Get.back() only fails after I perform an await on my HTTP Post request.
I also added the print statements, and I get them both, but the page doesn't go back.

I'll try to get a minimal version together to reproduce it.

Thanks

@jonataslaw
Copy link
Owner

I tried anyway, I couldn't reproduce the error. He is apparently working properly.

void main() {
  runApp(MaterialApp(
    title: 'Test async call',
    navigatorKey: Get.key,
    home: TestScreen(),
  ));
}

class API {
  static Future<dynamic> getTestError() async {
    final response = await Dio().get('https://www.google.com');
    if (response.statusCode == 200) {
      print(response);
      Get.back();
      return response;
    } else {
      // Now you can made this
      print('error on API');
      Get.back();
    }
  }
}

class TestScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          child: FlatButton(
            color: Colors.blue,
            child: Text('go to nextroute'),
            onPressed: () {
              Get.to(TestScreenTwo());
            },
          ),
        ),
      ),
    );
  }
}

class TestScreenTwo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Container(
          child: FlatButton(
            color: Colors.red,
            child: Text('call api'),
            onPressed: () {
              API.getTestError();
            },
          ),
        ),
      ),
    );
  }
}

@dayofbrian
Copy link
Author

dayofbrian commented Apr 22, 2020

Okay, I've replicated the issue using a minor change to your sample code, it took me a while to figure out. If you put a Get.snackbar just before your Dio().get call it doesn't go back.

class API {
  static Future<dynamic> getTestError() async {
    Get.snackbar("title", "message");
    final response = await Dio().get('https://www.google.com');
    if (response.statusCode == 200) {
      print(response);
      Get.back();
      return response;
    } else {
      // Now you can made this
      print('error on API');
      Get.back();
    }
  }
}

@jlubeck
Copy link

jlubeck commented Apr 22, 2020

Well, wouldn't the Get.back close the Snackbar in that situation?

@jonataslaw
Copy link
Owner

jonataslaw commented Apr 22, 2020

class API {
static Future getTestError() async {
Get.snackbar("title", "message");
final response = await Dio().get('https://www.google.com');
if (response.statusCode == 200) {
print(response);
Get.back();
return response;
} else {
// Now you can made this
print('error on API');
Get.back();
}
}
}

This behavior is expected, Get allows you to close a snackbar, dialog or bottomsheet dynamically, from anywhere.
If any of these are open, they will be closed, so you would need another Get.back(); to close, right?
Ideally, you should control when a dialog, snackbar or bottomsheet is open. If you can't control this, you should create some logic like this:

if(Get.isSnackbarOpen || Get.isDialogOpen || Get.isBottomsheetOpen){
Get.close(2);
} else {
Get.back();
}

Or maybe (much safer - recommended)

if(Get.isSnackbarOpen || Get.isDialogOpen || Get.isBottomsheetOpen){
navigator.popUntil((route) {
      return (!Get.isSnackbarOpen && !Get.isDialogOpen && !Get.isBottomsheetOpen);
});
}
Get.back();

Remembering that you need to add GetObserver to your MaterialApp to gain access to these features.

@dayofbrian
Copy link
Author

Okay, that wasn't clear in your documentation. It just states 'To return to previous screen'.

Thanks for the clarification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants