Flutter Navigation: Failed assertion: line 4949 pos 12: 'newRoute._navigator == null': is not true

34 Views Asked by At

My app uses Bloc as it's state management. When the app receive state OAuthSignedIn(), the _navigator in

WidgetsBinding.instance.addPostFrameCallback((_) {
  log('Here');
  _navigator.pushAndRemoveUntil(
    HomePage.route,
    (route) => true,
  );
});

Gives error 'newRoute._navigator == null': is not true.

Full code:

class App extends StatelessWidget {
  App({super.key});

  final SupabaseClient supabaseClient = Supabase.instance.client;

  @override
  Widget build(BuildContext context) {
    return BlocProvider<AppBloc>(
      create: (context) => AppBloc(supabaseClient: supabaseClient),
      child: const AppView(),
    );
  }
}

class AppView extends StatefulWidget {
  const AppView({super.key});

  @override
  State<AppView> createState() => _AppViewState();
}

class _AppViewState extends State<AppView> {
  final _navigatorKey = GlobalKey<NavigatorState>();
  NavigatorState get _navigator => _navigatorKey.currentState!;

  StreamSubscription<AuthState>? _authSubscription;

  @override
  void initState() {
    handleOAuthListener();
    super.initState();
  }

  void handleOAuthListener() {
    SupabaseClient supabase = Supabase.instance.client;

    _authSubscription =
        supabase.auth.onAuthStateChange.listen((AuthState data) {
      log("handleOAuthListener ${data.event.name}");
      handleOAuthSignIn(data);
    });
  }

  void handleOAuthSignIn(AuthState data) {
    final event = data.event;
    switch (event) {
      case AuthChangeEvent.initialSession:
        log("Getting initial user");
        context.read<AppBloc>().add(GetInitialUser());

      case AuthChangeEvent.signedIn:
        log("OAuth Sign in success");
        context.read<AppBloc>().add(OAuthSignInSuccessfullEvent());

      case AuthChangeEvent.tokenRefreshed:
        log("OAuth token refreshed");
        context.read<AppBloc>().add(OAuthSignInSuccessfullEvent());
      default:
        break;
    }
  }

  @override
  void dispose() {
    _authSubscription?.cancel();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: _navigatorKey,
      title: 'MyApp',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      builder: (context, child) {
        return BlocListener<AppBloc, AppState>(
          listenWhen: (previous, current) => current != previous,
          listener: (context, state) {
            switch (state) {
              case OAuthSignedIn():
                WidgetsBinding.instance.addPostFrameCallback((_) {
                  log('Here');
                  _navigator.pushAndRemoveUntil(
                    HomePage.route,
                    (route) => true,
                  );
                });
                break;

              case OAuthSignedOut():
                WidgetsBinding.instance.addPostFrameCallback((_) {
                  log('Signed out here');
                  _navigator.pushAndRemoveUntil(
                    LoginPage.route,
                    (route) => true,
                  );
                });
                break;

              default:
                break;
            }
          },
          child: child,
        );
      },
      onGenerateRoute: (_) => SplashPage.route,
    );
  }
}

I did tried changing the WidgetsBinding to ScheduleBinding and using Future.delayed (with various durations) instead of both bindings, but it doesn't seem to solve the issue

Also, using Future.delayed changed the error to '!_debugLocked': is not true.

0

There are 0 best solutions below