Search code examples
flutterblocflutter-bloc

BlocProvider.of cannot find the Bloc created earlier


When trying to intercept the backbutton press, I want to reset the state of the main Bloc to the initial state, so I want to add a kind of reset event when pressing back. I can't wrap my head around as to why this is not working.

This is the error I am getting, and normally I can solve this by setting the BlocProvider earlier in the hierarchy.

_onBackPressed Builder Builder(dependencies: [ScrollConfiguration, _LocalizationsScope-[GlobalKey#488f2]])

======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
        BlocProvider.of() called with a context that does not contain a WatchSkSelectClubBloc.

        No ancestor could be found starting from the context that was passed to BlocProvider.of().

        This can happen if the context you used comes from a widget above the BlocProvider.

        The context used was: Builder(dependencies: [ScrollConfiguration, _LocalizationsScope-[GlobalKey#488f2]])
        
When the exception was thrown, this was the stack: 
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 294:3                   throw_
packages/flutter_bloc/src/bloc_provider.dart 99:7                                             of
packages/tennismanagerapp/watchPages/scoreKeeper/view/watch_sk_selectTornooi_page.dart 65:18  [_onBackPressed]
packages/tennismanagerapp/watchPages/scoreKeeper/view/watch_sk_selectTornooi_page.dart 84:19  
packages/flutter/src/material/action_buttons.dart 69:11                                       
packages/flutter/src/material/ink_well.dart 1183:21                                           handleTap
packages/flutter/src/gestures/recognizer.dart 275:24                                          invokeCallback
packages/flutter/src/gestures/tap.dart 652:11                                                 handleTapUp
packages/flutter/src/gestures/tap.dart 309:5                                                  [_checkUp]
packages/flutter/src/gestures/tap.dart 242:7                                                  handlePrimaryPointer
packages/flutter/src/gestures/recognizer.dart 630:9                                           handleEvent
packages/flutter/src/gestures/pointer_router.dart 98:7                                        [_dispatch]
packages/flutter/src/gestures/pointer_router.dart 143:9                                       
dart-sdk/lib/_internal/js_dev_runtime/private/linked_hash_map.dart 21:7                       forEach
packages/flutter/src/gestures/pointer_router.dart 141:17                                      [_dispatchEventToRoutes]
packages/flutter/src/gestures/pointer_router.dart 127:7                                       route
packages/flutter/src/gestures/binding.dart 488:5                                              handleEvent
packages/flutter/src/gestures/binding.dart 468:14                                             dispatchEvent
packages/flutter/src/rendering/binding.dart 439:11                                            dispatchEvent
packages/flutter/src/gestures/binding.dart 413:7                                              [_handlePointerEventImmediately]
packages/flutter/src/gestures/binding.dart 376:5                                              handlePointerEvent
packages/flutter/src/gestures/binding.dart 323:7                                              [_flushPointerEventQueue]
packages/flutter/src/gestures/binding.dart 292:9                                              [_handlePointerDataPacket]
lib/_engine/engine/platform_dispatcher.dart 1289:5                                            invoke1
lib/_engine/engine/platform_dispatcher.dart 273:5                                             invokeOnPointerDataPacket
lib/_engine/engine/pointer_binding.dart 168:30                                                [_onPointerData]
lib/_engine/engine/pointer_binding.dart 791:20                                                
lib/_engine/engine/pointer_binding.dart 720:7                                                 
lib/_engine/engine/pointer_binding.dart 317:9                                                 loggedHandler
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 574:37              _checkAndCall
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 579:39              dcall
Handler: "onTap"
Recognizer: TapGestureRecognizer#68594
  debugOwner: GestureDetector
  state: possible
  won arena
  finalPosition: Offset(23.0, 15.0)
  button: 1
  sent tap down
====================================================================================================

But now the Bloc is provided, as I can see in the Widget Tree. [![WidgetTree][1]][1]

Also, when trying to put breakpoints in the code itself, it shows those breakpoints as invalid, and in any other modules they do work as expected..

Here is the code that calls the Widget:

            Navigator.of(context).push(

          MaterialPageRoute(
              builder: (context) =>
                  WatchSkSelectTornooiPage(
                    parentContext: context,
                    clubname:
                    state.clickedOnClubnameFromDbForWedstrijdtafel,
                    anonymousAllowed: true,
                    activeWts: state.activeWts,
                    tournamentId:
                    state.clickedOnTournamentIdFromDbForWedstrijdtafel,
                  )),
        );

And The code that does throws the exception:

    class WatchSkSelectTornooiPage extends StatefulWidget {
  final BuildContext parentContext;
  final bool anonymousAllowed;
  final String clubname;
  final List<WedstrijdtafelEntry> activeWts;
  final int tournamentId;

  WatchSkSelectTornooiPage({
    Key? key,
    required this.parentContext,
    required this.clubname,
    required this.anonymousAllowed,
    required this.activeWts,
    required this.tournamentId,
  }) : super(key: key) {
    if (kDebugMode) {
      print("WatchSkSelectTornooiPage constructor");
    }
  }

  @override
  State<WatchSkSelectTornooiPage> createState() =>
      _WatchSkSelectTornooiPageState();
}

class _WatchSkSelectTornooiPageState extends State<WatchSkSelectTornooiPage> {
  @override
  void initState() {
    super.initState();
    BackButtonInterceptor.add(myInterceptor);
  }

  @override
  void dispose() {
    BackButtonInterceptor.remove(myInterceptor);
    super.dispose();
  }

  bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
    if (Navigator.of(context).canPop()) {
      _onBackPressed(context);
      return true;
    } else {
      return false;
    }
  }

  void _onBackPressed(context) {
    // Set state back to init to refresh clublist
    if (kDebugMode) {
      print("_onBackPressed ${widget.parentContext} ${context}");
    }
    BlocProvider.of<WatchSkSelectClubBloc>(context)
        .add(WatchSkRefreshSelectClubEvent());
    Navigator.of(context).pop();
  }

  @override
  Widget build(BuildContext context) {
    // implementation is here
}

Is there anything wrong with the building of my project, as this confuses me greatly.

Thanks a lot. [1]: https://i.sstatic.net/pJtuU.png


Solution

  • You have a few options here.

    First, you could try pass WatchSkSelectClubBloc instance to the WatchSkSelectTornooiPage. But after I wrote it, it looks like a questionable move as for me..

    Second, you could await for return from this page to the previous, from where you've opened WatchSkSelectTornooiPage, something like this:

        ...
        
    await Navigator.of(context).pushNamed(...);
    BlocProvider.of<WatchSkSelectClubBloc>(context).add(WatchSkRefreshSelectClubEvent());
            
        ...