Поставщик репозитория в библиотеке flutter_bloc не предоставляет репозиторий при отправке нового маршрута - PullRequest
1 голос
/ 25 сентября 2019

Я использую библиотеку flutter_bloc для разработки своего приложения.В дополнение к BlocProvider я использую Repository Provider, так как я буду широко использовать определенный репозиторий в своем приложении.Но у меня проблема с контекстом.Ниже мой код:

main.dart

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  BlocSupervisor.delegate = SimpleBlocDelegate();
  PrefsRepository.prefs = await SharedPreferences.getInstance();
  appRepository _appRepository = AppRepository();
  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
      .then((_) {
    runApp(
      BlocProvider(
        builder: (context) =>
            AuthenticationBloc(appRepository: _appRepository)..dispatch(AppStarted()),
        child: App(appRepository: _appRepository,),
      ),
    );
  });
}

class App extends StatelessWidget {
  final AppRepository _appRepository;

  App({AppRepository appRepository})
      : assert(appRepository != null),
        _appRepository = appRepository;

  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
        builder: (BuildContext context, AuthenticationState state) {
          if (state is AuthenticationAuthenticated) {
        ....
          }
          if (state is AuthenticationUnauthenticated) {
            return SafeArea(
              top: false,
              bottom: false,
              child: RepositoryProvider(
                builder: (context) => _appRepository,
                child: LoginPage(firebaseMessaging: _firebaseMessaging),
              ),
            );
          }
          if (state is AuthenticationLoading) {
           .....
          }

        },
      ),
    );
  }
}

login_page.dart

class LoginPage extends StatelessWidget {
  final FirebaseMessaging _firebaseMessaging;

  LoginPage({
    Key key,
    @required FirebaseMessaging firebaseMessaging,
  })  : assert(firebaseMessaging != null),
        _firebaseMessaging = firebaseMessaging,
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider(
        builder: (context) => LoginBloc(
          appRepository: RepositoryProvider.of<AppRepository>(context),
          firebaseMessaging: _firebaseMessaging,
        ),
        child: LoginForm(
          firebaseMessaging: _firebaseMessaging,
        ),
      ),
    );
  }
}

login_form.dart

class LoginForm extends StatefulWidget {
  final FirebaseMessaging _firebaseMessaging;

  LoginForm({
    Key key,
    @required FirebaseMessaging firebaseMessaging,
  })  : assert(firebaseMessaging != null),
        _firebaseMessaging = firebaseMessaging,
        super(key: key);

  @override
  State<LoginForm> createState() => _LoginFormState();
}

class _LoginFormState extends State<LoginForm> {
.....

  @override
  Widget build(BuildContext context) {
    double _width = MediaQuery.of(context).size.width;

EdgeInsets _contentPadding =  EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0);

    return BlocListener(
      bloc: _loginBloc,
      listener: (BuildContext context, LoginState state) {
      .....
      },
      child: BlocBuilder<LoginBloc, LoginState>(
        builder: (
          BuildContext context,
          LoginState state,
        ) {
            return ...
            ....
                    RegisterButton(
                      firebaseMessaging: widget._firebaseMessaging,
                    ),

                  ],
                ),
              )
            ],
          );
        },
      ),
    );
  }
}

register_button.dart

class RegisterButton extends StatelessWidget {
  final FirebaseMessaging _firebaseMessaging;

  RegisterButton({
    Key key,
    @required FirebaseMessaging firebaseMessaging,
  })  : assert(firebaseMessaging != null),
        _firebaseMessaging = firebaseMessaging,
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        Text("Don't have an account?", style: TextStyle(color: Colors.black)),
        SizedBox(width: 4.0),
        GestureDetector(
          child: Text("Register here!",
              style: TextStyle(
                  color: Color(0xFF585B8D), fontWeight: FontWeight.w500)),
          onTap: () {
            Navigator.of(context).push(
              MaterialPageRoute(builder: (context) {
                return RegisterPage(
                  firebaseMessaging: _firebaseMessaging,
                );
              }),
            );
          },
        )
      ],
    );
  }

register_page.dart

class RegisterPage extends StatelessWidget {
  final FirebaseMessaging _firebaseMessaging;

  RegisterPage({
    Key key,
    @required FirebaseMessaging firebaseMessaging,
  })  : assert(firebaseMessaging != null),
        _firebaseMessaging = firebaseMessaging,
        super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider(
        builder: (context) => RegisterBloc(
          appRepository: RepositoryProvider.of<AppRepository>(context),
          firebaseMessaging: _firebaseMessaging,
        ),
        child: RegisterForm(),
      ),
    );
  }
}

Вопрос:

Я получаю сообщение об ошибке, когда нажимаю кнопку регистрации в форме входа в систему, в которой говорится следующее:

No ancestor could be found starting from the context that was passed to RepositoryProvider.of<AppRepository>().

This can happen if:
1. The context you used comes from a widget above the RepositoryProvider.
2. You used MultiRepositoryProvider and didn't explicity provide the RepositoryProvider types.

Good: RepositoryProvider<AppRepository>(builder: (context) => AppRepository())
Bad: RepositoryProvider(builder: (context) => AppRepository()).

The context used was: BlocProvider<RegisterBloc>(dirty, state: _DelegateWidgetState#a87b2(lifecycle state: created))

Почему я получаюэта ошибка?Эта проблема, похоже, будет исправлена, если я поставлю провайдера репозитория в качестве дочернего элемента blocprovider, а приложение - в качестве дочернего провайдера репозитория в основной функции, а затем удаляю неиспользуемые провайдеры репозитория в App ().Я предполагаю, что проблема заключается в том, чтобы нажимать маршрут страницы материала от кнопки.Я не думаю, что я понимаю, как контекст или провайдер точно работает во Flutter.Я думал, что провайдер будет искать дерево виджетов для репозитория / блока. Разве пробивание маршрута как-то нарушает эту непрерывность?

1 Ответ

1 голос
/ 26 сентября 2019

Когда вы используете Navigator.of(context).push или Navigator.of(context).pushNamed выдвинутый виджет не является дочерним элементом виджета, который вызывает Navigator.of(context).push или Navigator.of(context).pushNamed, этот виджет является дочерним по отношению к ближайшему экземпляру Navigator, который охватывает данныйcontext, в вашем случае Navigator создается MaterialApp, поэтому, если вы хотите указать Repository или Bloc для других routes, Provider должен быть родителем Navigator, в вашем случае должен быть родитель MaterialApp.

...