Search code examples
fluttercallbacknavigator

Navigator inside QuickAlert Dialog does not work


In flutter, I have this Screen deep down in my MaterialApp's widget tree:

class ItemDetailsScreen extends StatefulWidget {
  ItemDetailsScreen();

  @override
  State<ItemDetailsScreen> createState() => _ItemDetailsScreenState();
}

class _ItemDetailsScreenState extends State<ItemDetailsScreen> {

 @override
  Widget build(BuildContext context) {

    bleController.onBleStatusChange('box_is_open', context);
    
    return Scaffold(....
} 

Future<void> onBleStatusChange() async {
...
QuickAlert.show(
        context: context,
        type: QuickAlertType.success,
        title: 'Box geöffnet!',
        text: 'Bitte entnimm jetzt das Item',
        confirmBtnText: 'Weiter',
        onConfirmBtnTap: () {
          Navigator.of(context).push(
              MaterialPageRoute(
                  builder: (context) => const MyNextScreen())); // ERROR
        }
      );
  }
}

I get this error meassage after apping on the confirm button in the QuickAlert dialog onConfirmBtnTap:

======== Exception caught by scheduler library =====================================================
The following assertion was thrown during a scheduler callback:
'package:flutter/src/widgets/navigator.dart': Failed assertion: line 4475 pos 12: '!_debugLocked': is not true.


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.md

When the exception was thrown, this was the stack: 
#2      NavigatorState._pushEntry (package:flutter/src/widgets/navigator.dart:4475:12)
#3      NavigatorState.push (package:flutter/src/widgets/navigator.dart:4412:5)
#4      GetNavigation.to (package:get/get_navigation/src/extension_navigation.dart:522:37)
#5      BleController._navigateToTestDeviceUI.<anonymous closure> (package:flutter_starter/controllers/ble_controller.dart:177:61)
#6      SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1175:15)
#7      SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1113:9)
#8      SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1015:5)
#9      _invoke (dart:ui/hooks.dart:148:13)
#10     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#11     _drawFrame (dart:ui/hooks.dart:115:31)
(elided 2 frames from class _AssertionError)
====================================================================================================

I also tried to add a small delay and to move the Navigation to a separate function:

onConfirmBtnTap: () async {
      await Future.delayed(Duration.zero);
      _navigateToMyNextScreen();
    },

...

void _navigateToMyNextScreen() {
        Navigator.of(Get.context!)
            .push(MaterialPageRoute(builder: (Get.context!) => MyNextScreen())));

  }

But the error was the exact same. I also tried passing the BuildContext into that new separate Method instead of getting it from GetX, but it's the same error. I also tried to navigate with GetX Get.to(() => MyNextScreen()) instead of using the Navigator, but that made no difference.

I also asked ChatGPT3, it gave a good looking response that I should separate it into a separate function, but I think that makes no sense and the error stayed the same.

ChatGPT ChatGPT_answer


Solution

  • Thanks for looking into it, I solved it now, the function onBleStatusChange() was called in the another function, which was called from within the build() function of also again another Screen, that was too much. I had to wrap everything with WidgetsBinding.instance.addPostFrameCallback()then it worked. In the end this solved it:

    @override
      Widget build(BuildContext context) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          QuickAlert.show(
            context: context,
            type: QuickAlertType.success,
            title: 'Box geöffnet!',
            text:
                'Bitte entnimm jetzt die ${this.boxesController!.currentItem.value.name}',
            confirmBtnText: 'Weiter',
            onConfirmBtnTap: () async {
           
             _navigateToTestDeviceUI();
            
          );
        });
        ...