当我尝试将添加到 Firebase 的值放入下拉按钮时,出现以下错误
方法 'data' 在 null.Receiver 上被调用:nullTried 调用:data()
我认为错误的原因是我无法将值从 Todo.dart 调用到 post_page.dart。
使用 debag,post_page.dart 中的 todolist 为空。
如果您能回答我将不胜感激。
post_page.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import "package:flutter/material.dart";
import 'package:habit_boddy/component/post/task_add_button.dart';
import 'package:habit_boddy/utils/constants.dart';
import 'package:habit_boddy/view/common/components/drop_text.dart';
import 'package:habit_boddy/view/common/components/post_caption_part.dart';
import 'package:habit_boddy/view/post/page/Todo.dart';
import 'package:habit_boddy/view/post/page/detail_page.dart';
import 'package:habit_boddy/view/post/page/picture_page.dart';
import 'package:habit_boddy/view/post/page/task_setting.dart';
import 'package:habit_boddy/view_models/post_view_model.dart';
import 'package:habit_boddy/view_models/todo_view_model.dart';
import 'package:provider/provider.dart';
import 'confirm_dialog.dart';
class PostPage extends StatefulWidget {
@override
_PostPageState createState() => _PostPageState();
}
class _PostPageState extends State<PostPage> {
final _captionController = TextEditingController();
@override
void initState() {
_captionController.addListener(_onCaptionUpdated);
super.initState();
}
@override
void dispose() {
_captionController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<ToDoViewModel>(
create:(_) => ToDoViewModel()..getRealtime(),
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.amber,
actions: [
ElevatedButton(
child: Text('Post'),
style: ElevatedButton.styleFrom(
primary: Colors.orange,
onPrimary: Colors.white,
),
onPressed: () => showConfirmedDialog(
context: context,
title: "Post",
content: "May I post?",
onConfirmed: (isConfirmed) {
if (isConfirmed) {
_post(context);
}
}))
],
),
body: Consumer<ToDoViewModel>(builder: (context, model, child) {
final todoList = model.todoList;
return DropdownButton<Todo>(
items: todoList.map((todo) =>
DropdownMenuItem<Todo>(
value: Todo(title: todo.title),
child: Text(todo.title),
)
).toList(),
);
}),
floatingActionButton:
Consumer<ToDoViewModel>(builder: (context, model, child) {
return FloatingActionButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(builder: (context) => TaskSetting()),
);
},
child: Icon(Icons.add),
);
}),
),
);
}
_onCaptionUpdated() {
final viewModel = Provider.of<PostViewModel>(context, listen: false);
viewModel.caption = _captionController.text;
print("caption: ${viewModel.caption}");
}
void _post(BuildContext context) {
final postViewModel = Provider.of<PostViewModel>(context, listen: false);
}
}
Widget build(BuildContext context) {
final postViewModel = Provider.of<PostViewModel>(context);
return Container(
child: Padding(
padding: const EdgeInsets.all(40.0),
child: SingleChildScrollView(
child: Column(
children: [
Row(
children: [
Expanded(
flex: 3,
child: Container(
child: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: DropText(),
),
height: 230),
),
Expanded(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(bottom: 155.0),
child: TaskAdd(),
)),
],
),
Container(
child: Padding(
padding: const EdgeInsets.only(top: 20.0),
child: DetailPost(),
),
height: 270),
Row(
children: [
PicturePage(),
postViewModel.imageFile == null
? Container()
: Container(
height: 60,
width: 60,
child: SingleChildScrollView(
child: PostCaptionPart(
from: PostCaptionOpenMode.FROM_POST,
),
),
)
],
),
],
),
),
),
);
}
Todo.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:habit_boddy/view_models/todo_view_model.dart';
class Todo {
final ToDoViewModel model;
String title = "";
DateTime createdAt;
Todo({DocumentSnapshot doc, this.title, this.model, this.createdAt}){
this.title = doc.data()["title"];
final Timestamp timestamp = doc.data()['createdAt'];
this.createdAt = timestamp.toDate();
}
}
答案 0 :(得分:0)
我相信这一行导致了错误。
DropdownMenuItem<Todo>(
value: Todo(title: todo.title),
您在 Todo 构造函数中调用 doc.data() 而不传递 doc 变量,因此在空变量上调用 .data() 。您应该先获取标题,然后在实例化 Todo 对象时将其传递给构造函数。
如果您确实需要传递 doc 变量,请说如果您需要它用于其他用途,请在构造函数中使其成为必需并断言它不为空。
Todo({@required DocumentSnapshot doc, this.title, this.model, this.createdAt}) : assert(doc != null){
...
}
您还应该研究 Dart 空值安全性,这将有助于避免此类问题。