flutter - 什么是正确的提供者为我的 DrawerNavigation 小部件?
问题描述
我正在开发一个具有 Google 登录功能的简单移动应用程序。
到目前为止,该应用程序一直在运行,但在最新步骤(实际登录)中,我收到以下错误
════════ Exception caught by widgets library ═══════════════════════════════════
Error: Could not find the correct Provider<AuthBlock> above this DrawerNavigation Widget
我已经尝试过通常的嫌疑人;确保正在导入正确的包,这是由于我在虚拟移动设备上运行,并且可能需要热重启。然而问题依然存在。
我原以为它会提示用户使用 Google 登录,但这显然没有发生。
我的代码如下,我相信错误来自第 54 行,它读取final authBlock = Provider.of(context); .
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:to_do_list/blocks/auth_block.dart';
import 'package:to_do_list/screens/home_screen.dart';
import 'package:to_do_list/screens/categories_screen.dart';
import 'package:to_do_list/screens/todos_by_category.dart';
import 'package:to_do_list/service/category_service.dart';
import 'package:flutter_signin_button/flutter_signin_button.dart';
class DrawerNavigation extends StatefulWidget {
@override
_DrawerNavigationState createState() => _DrawerNavigationState();
}
class _DrawerNavigationState extends State<DrawerNavigation> {
//List<Widget> _categoryList = List<Widget>(); //Has been depricated
List<Widget> _categoryList = List<Widget>.generate(0, (index) {
//Widget obj = Widget();
//obj.id = index;
return;
});
CategoryService _categoryService = CategoryService();
@override
initState() {
super.initState();
getAllCategories();
}
getAllCategories() async {
var categories = await _categoryService.readCategories();
categories.forEach((category) {
setState(() {
_categoryList.add(InkWell(
onTap: () => Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => new TodosByCategory(
category: category['name'],
))),
child: ListTile(
title: Text(category['name']),
),
));
});
});
}
@override
Widget build(BuildContext context) {
final authBlock = Provider.of<AuthBlock>(context);
return Container(
child: Drawer(
child: ListView(
children: <Widget>[
// UserAccountsDrawerHeader(
// currentAccountPicture: CircleAvatar(
// backgroundImage: NetworkImage(
// 'https://cdn.shopify.com/s/files/1/1733/6579/products/product-image-602960373_1024x1024@2x.jpg')),
// accountName: Text('Meena Bobeena'),
// accountEmail: Text('meena@happycat.com'),
// decoration: BoxDecoration(color: Colors.blue),
// ),
Column(
children: [
SignInButton(
Buttons.Google,
onPressed: () => authBlock.loginWithGoogle(),
),
],
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(builder: (context) => (HomeScreen()))),
),
ListTile(
leading: Icon(Icons.view_list),
title: Text('Categories'),
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (context) => (CategoriesScreen()))),
),
Divider(),
Column(
children: _categoryList,
)
],
),
),
);
}
}
根据要求,以下是 DrawerNavigation 的调用方式。
import 'package:flutter/material.dart';
import 'package:to_do_list/helpers/drawer_navigation.dart';
import 'package:to_do_list/screens/todo_screen.dart';
import 'package:to_do_list/service/todo_service.dart';
import 'package:to_do_list/models/todo.dart';
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
TodoService _todoService;
//List<Todo> _todoList = List<Todo>(); // Has been deprecated
List<Todo> _todoList = List<Todo>.generate(0, (index) {
Todo obj = Todo();
obj.id = index;
return obj;
});
@override
initState() {
super.initState();
getAllTodos();
}
getAllTodos() async {
_todoService = TodoService();
//_todoList = List<Todo>(); //Has been depricated
_todoList = List<Todo>.generate(0, (index) {
Todo obj = Todo();
obj.id = index;
return obj;
});
var todos = await _todoService.readTodos();
todos.forEach((todo) {
setState(() {
var model = Todo();
model.id = todo['id'];
model.title = todo['title'];
model.description = todo['description'];
model.category = todo['category'];
model.todoDate = todo['todoDate'];
model.isFinished = todo['isFinished'];
_todoList.add(model);
});
});
}
_deleteFormDialog(BuildContext context, categoryId) {
return showDialog(
context: context,
barrierDismissible: true,
builder: (param) {
return AlertDialog(
actions: <Widget>[
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red),
foregroundColor: MaterialStateProperty.all(Colors.white)),
onPressed: () async {
Navigator.pop(context);
},
child: Text('Cancel'),
),
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green),
foregroundColor: MaterialStateProperty.all(Colors.white)),
// This doesn't delete :'(
onPressed: () async {
var result = await _todoService.deleteTodos(categoryId);
//print(result);
if (result > 0) {
print(result);
Navigator.pop(context);
getAllTodos();
_showSuccessSnackBar(Text('Deleted'));
}
},
child: Text('Delete'),
),
],
title: Text('Are you sure you wish to delete this To Do item ?'),
);
});
}
_showSuccessSnackBar(message) {
var _snackBar = SnackBar(content: message);
ScaffoldMessenger.of(context).showSnackBar(_snackBar);
//_globalKey.currentState.showSnackBar(_snackBar); === Depreciated
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Meenas To Do List')),
drawer: DrawerNavigation(),
body: ListView.builder(
itemCount: _todoList.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.only(top: 8, left: 8, right: 8),
child: Card(
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(_todoList[index].title ?? 'No Title'),
IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () {
_deleteFormDialog(context, _todoList[index].id);
},
)
],
),
subtitle: Text(_todoList[index].category ?? 'No Category'),
trailing: Text(_todoList[index].todoDate ?? 'No Date'),
),
),
);
}),
floatingActionButton: FloatingActionButton(
onPressed: () => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) => TodoScreen())),
child: Icon(Icons.add)),
);
}
}
这是我实例化提供程序的代码
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:to_do_list/service/auth_service.dart';
class AuthBlock {
final authService = AuthService();
final googleSignIn = GoogleSignIn(scopes: ['email']);
Stream<User> get currentUser => authService.currentUser;
loginWithGoogle() async {
try {
final GoogleSignInAccount googleUser = await googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
idToken: googleAuth.idToken,
accessToken: googleAuth.accessToken,
);
//Firebase Sign In
final result = await authService.signInWithCredential(credential);
print('${result.user.displayName}');
} catch (error) {
print(error);
}
}
logout() {
authService.logout();
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:to_do_list/src/app.dart';
void main() => runApp(App());
解决方案
您是否使用提供商打包了您的应用程序?例如,就像你在这里看到的
runApp(
/// Providers are above [MyApp] instead of inside it, so that tests
/// can use [MyApp] while mocking the providers
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Counter()),
],
child: const MyApp(),
),
);
推荐阅读
- r - r- ggplot2 颜色和填充不起作用
- java - 有没有办法使用 Jackson(或类似的库)针对现有的 Java 对象值对 JSON 对象键进行拼写检查?
- c++ - 为什么声明私有基类会使类型名称无法访问?
- c++ - Switch 在 while 循环中不断进入默认情况
- php - 在codeigniter3.0中重定向到其他功能后,会话自动取消设置
- class - 在堆栈上分配 D 类
- c# - 将 ASP Classic 数学语句转换为 Razor
- java - 从 Java 中不断更新的文件中读取新数据
- c# - 如何确定一个值是由 NHibernate C# 还是由应用程序代码设置的?
- microservices - 事件溯源 - 事件流说明