Flutter 如何在上下文之间共享集团

Flutter 如何在上下文之间共享集团,flutter,bloc,Flutter,Bloc,在使用showDialog导航到新上下文后,我尝试访问在应用程序根目录附近创建的bloc实例。但是,如果我像往常一样尝试获取bloc,通过像_thisBlocInstance=BlocProvider.ofcontext这样的上下文获取它,我会得到一个错误,表明此上下文中没有提供bloc 我假设这是因为showDialog builder方法为对话框中的小部件分配了一个新的上下文,而这些小部件不知道我试图查找的Bloc,用户登录后立即实例化: @override Widget build(B

在使用showDialog导航到新上下文后,我尝试访问在应用程序根目录附近创建的bloc实例。但是,如果我像往常一样尝试获取bloc,通过像_thisBlocInstance=BlocProvider.ofcontext这样的上下文获取它,我会得到一个错误,表明此上下文中没有提供bloc

我假设这是因为showDialog builder方法为对话框中的小部件分配了一个新的上下文,而这些小部件不知道我试图查找的Bloc,用户登录后立即实例化:

  @override
Widget build(BuildContext context) {
  _authBloc = BlocProvider.of<AuthBloc>(context);
  _accountBloc = AccountBloc(authBloc: _authBloc);

  return BlocProvider(
    bloc: _accountBloc,

 ....
在EventDialog中,我再次尝试查找具有上下文的bloc:

@override
void build(BuildContext context) {

  _accountBloc = BlocProvider.of<AccountBloc>(context);
  _userMenuItems = _accountBloc.usersInAccount
    .map((user) => DropdownMenuItem(
          child: Text(user.userName),
          value: user.userId,
        ))
    .toList();
}
这将失败,错误为“getter bloc在null上被调用”,或者,没有该类型的bloc附加到此上下文

在使用showDialog或导航到新上下文后,是否有某种方法可以仅从上下文访问bloc

这是bloc provider类:

import 'package:flutter/material.dart';

//This class is a generic bloc provider from https://www.didierboelens.com/2018/08/reactive-programming---streams---bloc/
//it allows easy access to the blocs by ancestor widgets and handles calling their dispose method

class BlocProvider<T extends BlocBase> extends StatefulWidget {
  BlocProvider({
    Key key,
    @required this.child,
    @required this.bloc,
  }): super(key: key);

  final T bloc;
  final Widget child;

  @override
  _BlocProviderState<T> createState() => _BlocProviderState<T>();

  static T of<T extends BlocBase>(BuildContext context){
    final type = _typeOf<BlocProvider<T>>();
    BlocProvider<T> provider = context.ancestorWidgetOfExactType(type);
    return provider.bloc;
  }

  static Type _typeOf<T>() => T;
}

class _BlocProviderState<T> extends State<BlocProvider<BlocBase>>{
  @override
  void dispose(){
    widget.bloc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context){
    return widget.child;
  }
}

abstract class BlocBase {
  void dispose();
}

我发现在新上下文中访问原始bloc的最佳方法是将对它的引用传递给管理新上下文逻辑的新bloc。为了保持代码模块化,每个bloc不应控制超过一页的逻辑或一件事情,例如用户的登录状态。因此,当我使用showDialog创建一个新的屏幕/上下文时,我还应该有一个处理该屏幕中的逻辑的新bloc。如果我需要对原始bloc的引用,我可以通过对话框小部件的构造函数将其传递给新bloc的构造函数,这样新bloc/上下文仍然可以访问原始bloc中的任何信息:

    child: FloatingActionButton(
      onPressed: () => showDialog(
        context: context,
        builder: (newContext) => NewEventDialog(
          accountBloc: BlocProvider.of<AccountBloc>(context),
        ),
      ).then((event) => eventsBloc.addEvent(event)),

...

class NewEventDialog extends StatelessWidget {
  final AccountBloc accountBloc;
  NewEventBloc _newEventBloc;

  NewEventDialog({this.accountBloc}) : assert(accountBloc != null);

  @override
  Widget build(BuildContext context) {
    _newEventBloc = NewEventBloc(accountBloc: accountBloc);

    return BlocProvider(
      bloc: _newEventBloc,
...

最后一个答案是可以的,但可以简化,那就是将Bloc转移到它的子部件

@override
Widget build(BuildContext context) {
  return Align(
    alignment: Alignment.bottomRight,
    child: Padding(
      padding: const EdgeInsets.all(18.0),
      child: FloatingActionButton(
        onPressed: () => showDialog(
          context: context,
          builder: (newContext) => EventDialog((
          accountBloc: BlocProvider.of<AccountBloc>(context),
        ),
        ).then(
          (val) => print(val)
        ),
        child: Icon(Icons.add),
      ),
    ),
  );
}


class NewEventDialog extends StatelessWidget {
  final AccountBloc accountBloc;

  NewEventDialog({this.accountBloc}) : assert(accountBloc != null);

@override
void build(BuildContext context) {

  _accountBloc = accountBloc;
  _userMenuItems = _accountBloc.usersInAccount
    .map((user) => DropdownMenuItem(
          child: Text(user.userName),
          value: user.userId,
        ))
    .toList();
}
到目前为止,我发现这个问题发生在通过页面路由访问小部件时。我们可以将Bloc小部件转移到widget来避免这个问题

@override
Widget build(BuildContext context) {
  return Align(
    alignment: Alignment.bottomRight,
    child: Padding(
      padding: const EdgeInsets.all(18.0),
      child: FloatingActionButton(
        onPressed: () => showDialog(
          context: context,
          builder: (newContext) => EventDialog((
          accountBloc: BlocProvider.of<AccountBloc>(context),
        ),
        ).then(
          (val) => print(val)
        ),
        child: Icon(Icons.add),
      ),
    ),
  );
}


class NewEventDialog extends StatelessWidget {
  final AccountBloc accountBloc;

  NewEventDialog({this.accountBloc}) : assert(accountBloc != null);

@override
void build(BuildContext context) {

  _accountBloc = accountBloc;
  _userMenuItems = _accountBloc.usersInAccount
    .map((user) => DropdownMenuItem(
          child: Text(user.userName),
          value: user.userId,
        ))
    .toList();
}