Flutter 中的 BlocProvider 错误及其修复方法

BlocProvider bug in Flutter and how to fix it

所以我在 BlocProvider 方面遇到了一些问题。这是我遇到的问题:

编辑:在主页上添加了 DrinkBloc 并更改了片段:

完整代码

   @override
  Widget build(BuildContext context) {
    print("Building entire food list scaffold");
    return Scaffold(
      appBar: AppBar(title: Text("FoodList")),
      //THE BLOCPROVIDER 
      body: BlocProvider(
      //the issue might be that it is DrinkBloc(), but I have 2 separate tables, one after another
        create: (BuildContext context) => DrinkBloc(),
        child: Column(children: [
          Row(
            children: [
              Text('Drinks'),
              Divider(),
              IconButton(
                  icon: Icon(Icons.add),
                  onPressed: () => Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (BuildContext context) => DrinkForm())))
            ],
          ),
          Expanded(
            child: Container(
              child: BlocConsumer<DrinkBloc, List<Drink>>(
                builder: (context, drinkList) {
                  return ListView.separated(
                    itemBuilder: (BuildContext context, int index) {
                      print("drinkList: $drinkList");

                      Drink drink = drinkList[index];
                      return ListTile(
                          title: Text("${drink.name}",
                              style: TextStyle(fontSize: 30)),
                          onTap: () => showDrinkDialog(context, drink, index));
                    },
                    itemCount: drinkList.length,
                    separatorBuilder: (BuildContext context, int index) =>
                        Divider(color: Colors.black),
                  );
                },
                listener: (BuildContext context, drinkList) {},
              ),
            ),
          ),
          Row(
            children: [
              Text('Foods'),
              Divider(),
              IconButton(
                  icon: Icon(Icons.add),
                  onPressed: () => Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (BuildContext context) => FoodForm())))
            ],
          ),
          Expanded(
            child: Container(
              child: BlocConsumer<FoodBloc, List<Food>>(
                builder: (context, foodList) {
                  return ListView.separated(
                    itemBuilder: (BuildContext context, int index) {
                      print("foodList: $foodList");

                      Food food = foodList[index];
                      return ListTile(
                          title:
                              Text(food.name, style: TextStyle(fontSize: 30)),
                          subtitle: Text(
                            "Calories: ${food.calories}\nVegan: ${food.isVegan}",
                            style: TextStyle(fontSize: 20),
                          ),
                          onTap: () => showFoodDialog(context, food, index));
                    },
                    itemCount: foodList.length,
                    separatorBuilder: (BuildContext context, int index) =>
                        Divider(color: Colors.black),
                  );
                },
                listener: (BuildContext context, foodList) {},
              ),
            ),
          ),
        ]),
      ),



  class DrinkBloc extends Bloc<DrinkEvent, List<Drink>> {
  @override
  List<Drink> get initialState => List<Drink>();

  @override
  Stream<List<Drink>> mapEventToState(DrinkEvent event) async* {
    if (event is SetDrinks) {
      yield event.drinkList;
    } else if (event is AddDrink) {
      List<Drink> newState = List.from(state);
      if (event.newDrink != null) {
        newState.add(event.newDrink);
      }
      yield newState;
    } else if (event is DeleteDrink) {
      List<Drink> newState = List.from(state);
      newState.removeAt(event.drinkIndex);
      yield newState;
    } else if (event is UpdateDrink) {
      List<Drink> newState = List.from(state);
      newState[event.drinkIndex] = event.newDrink;
      yield newState;
    }
  }
}

片段:

body: BlocProvider(
    create: (BuildContext context) => DrinkBloc(),
    child: Column(children: [
      Row(

我现在遇到的错误基本上是当我点击按钮添加饮料时('Drinks' 旁边的按钮)

No ancestor could be found starting from the context that was passed to BlocProvider.of<DrinkBloc>().
The context used was: DrinkForm(state: _DrinkFormState#5d9c5)
BlocProvider.of() called with a context that does not contain a Bloc of type DrinkBloc.

现在看起来如何(底部有效,但上部饮料无效,可能是因为我将整个东西都包裹在 DrinkBloc 中,不知道如何更改它 )

main.dart

   class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider<FoodBloc>(
      create: (context) => FoodBloc(),
      child: MaterialApp(
        title: 'Sqflite Tutorial',
        theme: ThemeData(
          primarySwatch: Colors.deepPurple,
        ),
        home: FoodList(),
      ),
    );
  }
}

您没有providing/injecting DrinkBloc进入小部件树。

因此,当您尝试使用 BlocConsumer 访问 DrinkBloc bloc 时,它会尝试查找该 bloc 的祖先。因为它丢失了,它会抛出那个特定的错误 BlocProvider.of() called with a context that does not contain a Bloc of type DrinkBloc.

对于 providing/injecting Drinkbloc 你可以使用 BlocProvider 如下:

BlocProvider(
  create: (BuildContext context) => BlocA(),
  child: ChildA(),
);

在任何地方调用它作为 BlocConsumer 的祖先。

例如:

Scaffold(
      appBar: AppBar(title: Text("FoodList")),
      body:  BlocProvider(
                 create: (BuildContext context) => DrinkBloc(),
               child: Column(children: [
                          ...
                          ],
         );

为了让 BlocConsumer 在上下文中工作,它应该知道它使用的 bloc,因此,called with a context that does not contain a Bloc of type DrinkBloc.

flutter_bloc 文档中,您必须像这样定义提供程序

BlocProvider(
  create: (BuildContext context) => DrinkBloc(),
  child: Widget("this widget's context contains DrinkBloc"),
);

因此,只需将它放在小部件树中您想要放置的位置的更高位置,并将 BlocConsumer 放在其中的任何位置。