首页 > 解决方案 > 错误:找不到正确的提供者在这个 Builder Widget 上方

问题描述

我正在开发一个小型的待办事项列表应用程序,而且我是这个Provider包的新手。我收到此错误:

错误:在此构建器小部件上方找不到正确的提供程序。发生这种情况是因为您使用了不包括您选择的提供者的“BuildContext”。

When the exception was thrown, this was the stack: 
#0      Provider._inheritedElementOf (package:provider/src/provider.dart:332:7)
#1      Provider.of (package:provider/src/provider.dart:284:30)
#2      HomePage.build.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:mytodolist/main.dart:57:36)
#3      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:994:20)
#4      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#9540a
  debugOwner: GestureDetector
  state: possible
  won arena
  finalPosition: Offset(308.6, 425.5)
  finalLocalPosition: Offset(34.8, 20.3)
  button: 1
  sent tap down

这是我的main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:mytodolist/TodoModel.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          brightness: Brightness.light,
          primaryColor: Colors.blue,
          accentColor: Colors.orange,
        ),
        home: ChangeNotifierProvider(
          create: (context) => TodoModel(),
          child: HomePage(),
        )
    );
  }
}


class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("mytodos"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showDialog(
              context: context,
              builder: (BuildContext context) {
                return AlertDialog(
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(8)),
                  title: Text("Add Todolist"),
                  content: TextField(
                    onChanged: (String value) {
                      Provider.of<TodoModel>(context, listen: false)
                          .addTitle(value);
                    },
                  ),
                  actions: <Widget>[
                    TextButton(
                        onPressed: () {
                          Provider.of<TodoModel>(context, listen: false)
                              .createTodos();
                          Navigator.of(context).pop();
                        },
                        child: Text("Add"))
                  ],
                );
              });
        },
        child: Icon(
          Icons.add,
          color: Colors.white,
        ),
      ),
      body: StreamBuilder(
          stream: FirebaseFirestore.instance.collection("MyTodos").snapshots(),
          builder: (context, snapshots) {
            if (snapshots.data == null) return CircularProgressIndicator();
            return Consumer<TodoModel>(builder: (context, todo, child) {
              return ListView.builder(
                  shrinkWrap: true,
                  itemCount: snapshots.data.docs.length,
                  itemBuilder: (context, index) {
                    DocumentSnapshot documentSnapshot =
                        snapshots.data.docs[index];
                    return Dismissible(
                        onDismissed: (direction) {
                          Provider.of<TodoModel>(context, listen: false)
                              .deleteTodos(documentSnapshot["todoTitle"]);
                        },
                        key: Key(documentSnapshot["todoTitle"]),
                        child: Card(
                          elevation: 4,
                          margin: EdgeInsets.all(8),
                          shape: RoundedRectangleBorder(
                              borderRadius: BorderRadius.circular(8)),
                          child: ListTile(
                            title: Text(documentSnapshot["todoTitle"]),
                            trailing: IconButton(
                              icon: Icon(Icons.delete),
                              color: Colors.red,
                              onPressed: () {
                                /*setState(() {
                                todos.removeAt(index);
                              });*/
                                Provider.of<TodoModel>(context, listen: false)
                                    .deleteTodos(documentSnapshot["todoTitle"]);
                              },
                            ),
                          ),
                        ));
                  });
            });
          }),
    );
  }
}

这是我的 TodoModel.dart:

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';

class TodoModel extends ChangeNotifier {
  // List todos = [];
  String todoTitle = "";

  createTodos() {
    DocumentReference documentReference =
    FirebaseFirestore.instance.collection("MyTodos").doc(todoTitle);
    // Map
    Map<String, String> todos = {"todoTitle": todoTitle};
    documentReference.set(todos).whenComplete(() =>
        print("$todoTitle created"));
  }

  deleteTodos(item) {
    DocumentReference documentReference =
    FirebaseFirestore.instance.collection("MyTodos").doc(item);
    documentReference.delete().whenComplete(() => print("$item deleted"));
  }

  addTitle(String title) {
    todoTitle = title;
  }
}

main.dart中,我相信我已经举起了ChangeNotifierProvider足够高的高度,可以让它的孩子、HomePage班级、使用Provider.of<TodoModel>(content).xxx. 为什么在Builder Widget上面还是会弹出找不到正确Provider的错误?

标签: flutterdartflutter-provider

解决方案


请使用HomePage' 上下文而不是showDialog' 构建器。

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {  // <<<<<<< USE THIS CONTEXT
    return Scaffold(
      appBar: AppBar(
        title: Text("mytodos"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          showDialog(
              context: context,
              builder: (BuildContext dialogContext) {  // <<<<<<< DO NOT USE THIS CONTEXT
                return AlertDialog(
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(8)),
                  title: Text("Add Todolist"),
                  content: TextField(
                    onChanged: (String value) {
                      // <<<<<<< context = HomePage's BuildContext
                      // <<<<<<< context != dialogContext
                      Provider.of<TodoModel>(context, listen: false)
                          .addTitle(value);
                    },
                  ),
                  actions: <Widget>[
                    TextButton(
                        onPressed: () {
                          // <<<<<<< context = HomePage's BuildContext
                          // <<<<<<< context != dialogContext
                          Provider.of<TodoModel>(context, listen: false)
                              .createTodos();
                          Navigator.of(context).pop();
                        },
                        child: Text("Add"))
                  ],
                );
              });
        },

推荐阅读