使用不包含 Bloc 类型的上下文调用 Flutter BlocProvider.of()

Posted

技术标签:

【中文标题】使用不包含 Bloc 类型的上下文调用 Flutter BlocProvider.of()【英文标题】:Flutter BlocProvider.of() called with a context that does not contain a Bloc of type 【发布时间】:2020-12-26 16:52:33 【问题描述】:

我正在从第一个屏幕导航到第二个屏幕。我在第二个屏幕中使用 Bloc Pattern。我收到以下错误:

 BlocProvider.of() called with a context that does not contain a Bloc of type 
   No ancestor could be found starting from the context that was passed to BlocProvider.of<MyBloc>().

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

下面是我的导航代码

 BlocProvider<MyBloc>(
            create: (context) => MyBloc());
        Navigator.push(context, MaterialPageRoute(builder: (context) 
          
          return SecondScreen(context);
        ));

下面是我的 SecondScreen 类

  class SecondScreen extends StatefulWidget 
  @override
  _SecondScreenState createState() => _SecondScreenState();
   

class _SecondScreenState extends State<SecondScreen> 
  MyBloc myBloc;

  @override
  void initState() 
    super.initState();
    myBloc = BlocProvider.of<MyBloc>(context);
    myBloc.add(FetchEvents());
 

  @override
  Widget build(BuildContext context) 
  return MaterialApp(
  home: Builder(
    builder: (context) 
      return Material(
        child: Scaffold(
          appBar: AppBar(
            title: Text("New Screen"),
            actions: <Widget>[
              IconButton(
                icon: Icon(Icons.refresh),
                onPressed: () 
                  myBloc.add(FetchEvents());
                ,
              ),
              IconButton(
                icon: Icon(Icons.info),
                onPressed: () 
                ,
              )
            ],
          ),
          body: Container(
            child: BlocListener<MyBloc, MyState>(
              listener: (context, state) 
                if (state is MyErrorState) 
                  Scaffold.of(context).showSnackBar(
                    SnackBar(
                      content: Text(state.message),
                    ),
                  );
                
              ,
              child: BlocBuilder<MyBloc, MyState>(
                builder: (context, state) 
                  if (state is MyInitialState) 
                    return buildLoading();
                   else if (state is MyLoadingState) 
                    return buildLoading();
                   else if (state is MyLoadedState) 
                    return buildArticleList(state.yList);
                   else if (state is MyErrorState) 
                    return buildErrorUi(state.message);
                  
                ,
              ),
            ),
          ),
        ),
      );
    ,
  ),
  );
   

 Widget buildLoading() 
  return Center(
  child: CircularProgressIndicator(),
   );
 

  Widget buildErrorUi(String message) 
 return Center(
  child: Padding(
    padding: const EdgeInsets.all(8.0),
    child: Text(
      message,
      style: TextStyle(color: Colors.red),
    ),
  ),
  );
 

  Widget buildArticleList(List<Data> data) 
  return ListView.builder(
  itemCount: data.length,
  itemBuilder: (ctx, pos) 
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: InkWell(
        child: ListTile(
         
          title: Text(data[pos].title),
          subtitle: Text(data[pos].shortDesc),
        ),
        onTap: () 
          // navigateToArticleDetailPage(context, articles[pos]);
        ,
      ),
    );
  ,
  );
  
 

我刚开始学习 bloc 并卡在这里.. 任何人都可以帮忙。

我没有在 main.dart 中添加任何与 bloc 相关的内容。有必要吗?

【问题讨论】:

【参考方案1】:

问题出在这部分:

 BlocProvider<MyBloc>(
            create: (context) => MyBloc());
        Navigator.push(context, MaterialPageRoute(builder: (context) 
          
          return SecondScreen(context);
        ));

把它改成这个大概会修复它:

 BlocProvider<MyBloc>(
            create: (context) => MyBloc());
        Navigator.push(context, MaterialPageRoute(
          builder: (routeContext) => SecondScreen(),
        ));

【讨论】:

The following SecondInitialState object was throwed building SecondScreen(state: _SecondScreenState#fe7f9): SecondInitialState 相关的导致错误的小部件是 SecondScreen lib/.../widgets/List.dart:49 抛出异常时,这是堆栈 #0 MyBloc.initialState #1 new Bloc #2 new MyBloc #3 _SecondScreenState.build. #4 BuilderStateDelegate.initDelegate 这似乎与您的集团问题无关,您的集团内部逻辑似乎有问题【参考方案2】:

将使用的widget 包裹在BlocProvider 内,这将提供正确的上下文以供使用。

BlocProvider(
      create: (BuildContext context) 
          return _yourBloc;
      ,
      child: Widget(

【讨论】:

【参考方案3】:

要在您正在导航的页面中使用相同的块,请使用 BlocProvider.value()。

改变

    Navigator.push(context, MaterialPageRoute(builder: (context)   
        return SecondScreen(context);
    ));

Navigator.push(context, MaterialPageRoute(builder: (context) 
  return BlocProvider<MyBloc>.value(
    value: BlocProvider.of<MyBloc>(context),
    child: SecondScreen(context),
  );
));

确保有一个 MyBloc 类型的父 BlocProvider。简单示例:

BlocProvider<MyBloc>(
  create: (context) => MyBloc(),
  child: Builder(
    builder: (context) => YourWidget(),//Wrap with Builder to access BlocProvider's context
  ),
);

我还强烈建议您查看this video 以获得更好的解释。

另外,this issue 可能会有所帮助。

【讨论】:

以上是关于使用不包含 Bloc 类型的上下文调用 Flutter BlocProvider.of()的主要内容,如果未能解决你的问题,请参考以下文章

使用不包含 Bloc 类型的上下文调用 BlocProvider.of()

BlocProvider.of() 使用不包含 Bloc<dynamic,dynamic> 类型的 Bloc 的上下文调用

使用不包含 PhoneAuthenticationBloc 类型的 Bloc 的上下文调用 BlocProvider.of()。扑

使用不包含 Bloc 类型的上下文调用 Flutter BlocProvider.of()

BlocProvider.of() 调用的上下文不包含 MyBloc 类型的 Bloc/Cubit

使用 bloc 更改屏幕