【问题标题】:I can not understand why the data in the DB is not updated - Flutter我不明白为什么数据库中的数据没有更新 - Flutter
【发布时间】:2022-01-15 18:32:16
【问题描述】:

我使用 DB SQLite,我想更新数据,但是当数据发生变化时,什么也没有发生,只有控制台中弹出一个警告(我附在下面)。我尝试了不同的选项,但我仍然不明白为什么我不能更新数据。虽然创建/删除效果很好,没有问题。更新数据库中的数据造成了这样的困难。如果您能告诉我可能是什么原因,我将不胜感激。

数据库

 Future<int> updateTodo(Todo todo) async {
    Database db = await database;
    return await db
        .update(todoTable, todo.toMap(), where: 'id = ?', whereArgs: [todo.id]);
  }

edit_todo_screen

class EditTodoScreen extends StatelessWidget {
  final Todo todo;
  EditTodoScreen({Key? key, required this.todo}) : super(key: key);

  final _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    _controller.text = todo.description;

    return BlocBuilder<TodoBloc, TodoState>(builder: (context, state) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Edit Todo'),
        ),
        body: _body(context),
      );
    });
  }

  Widget _body(context) {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: Column(
        children: [
          TextField(
            controller: _controller,
            autocorrect: true,
            decoration: const InputDecoration(hintText: 'Enter todo message'),
          ),
          const SizedBox(
            height: 10.0,
          ),
          InkWell(
            onTap: () {
              BlocProvider.of<TodoBloc>(context).add(
                UpdateTodos(
                  todo,
                  _controller.text,
                ),
              );
              Navigator.pop(context);
            },
            child: _updateBtn(context),
          )
        ],
      ),
    );
  }

todo_bloc

on<UpdateTodos>((event, emit) async {
  await todoRepository.updateTodo(event.todo);
  final List<Todo> _loadedTodoList = await todoRepository.getAllTodos();
  emit(TodoLoadedState(loadedUser: _loadedTodoList));
});

todo_event

class UpdateTodos extends TodoEvent {
  final Todo todo;

  const UpdateTodos(this.todo);
  @override
  List<Object> get props => [todo];
}

待办事项列表

class TodoList extends StatefulWidget {
  @override
  State<TodoList> createState() => _TodoListState();
}

class _TodoListState extends State<TodoList> {
  @override
  void initState() {
    super.initState();
    BlocProvider.of<TodoBloc>(context).add(LoadTodos());
  }

  @override
  void dispose() {
    BlocProvider.of<TodoBloc>(context).close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final TodoBloc todoBloc = context.read<TodoBloc>();
    return BlocBuilder<TodoBloc, TodoState>(builder: (context, state) {
      if (state is TodoEmptyState) {
        return const Center(
          child: Text(
            'No Todo',
            style: TextStyle(fontSize: 20.0),
          ),
        );
      }

      if (state is TodoLoadingState) {
        return const Center(child: CircularProgressIndicator());
      }

      if (state is TodoLoadedState) {
        return ListView.builder(
            physics: const NeverScrollableScrollPhysics(),
            shrinkWrap: true,
            itemCount: state.loadedUser.length,
            itemBuilder: (context, index) => ListTile(
                  title: Column(children: [
                    Text('${state.loadedUser[index].description}'),
                    Text('${state.loadedUser[index].id}'),
                  ]),
                  trailing: IconButton(
                    onPressed: () {
                      todoBloc.add(DeleteTodos(id: state.loadedUser[index].id));
                      // todoBloc.add(LoadTodos());
                    },
                    icon: const Icon(Icons.delete),
                  ),
                  onTap: () {
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                          builder: (context) => EditTodoScreen(
                                todo: Todo(
                                    description:
                                        '${state.loadedUser[index].description}'),
                              )),
                    );

todo_model

class Todo {
  int? id;
  late String description;
  // bool isDone = false;

  Todo({this.id, required this.description});

  Map<String, dynamic> toMap() {
    final map = <String, dynamic>{};
    map['id'] = id;
    map['description'] = description;
    // map['isDone'] = isDone == false ? 0 : 1;
    return map;
  }

  Todo.fromMap(Map<String, dynamic> map) {
    id = map['id'];
    description = map['description'];
    // isDone = map['isDone'] == 0 ? false : true;
  }
}

todo_repository

class TodoRepository {
  final db = DBProvider();

  Future getAllTodos() => db.getTodos();

  Future insertTodo(Todo todo) => db.createTodo(todo);

  Future updateTodo(Todo todo) => db.updateTodo(todo);

  Future deleteTodo(int id) => db.deleteTodo(id);

  Future deleteAllTodo(int id) => db.deleteAllTodo(id);
}

当我点击按钮时,这是控制台中的警告

【问题讨论】:

  • 能否将代码也包含在Todo 类中?
  • 好的,打开
  • 不,我的意思是 Todo 模型,您传递给 updateTodo 并具有 ID、描述等的模型。
  • 明白,补充:)

标签: flutter dart flutter-layout


【解决方案1】:
return await db
        .update(todoTable, todo.toMap(), where: 'id = ?', whereArgs: [todo.id]);

您在这里遇到的错误是因为 todo id 为空。这就是你在路由到EditTodoScreen时所做的:

Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => EditTodoScreen(
          todo: Todo(
            description: '${state.loadedUser[index].description}',
          ),
        ),
      ),
    );

注意这里的待办事项:

todo: Todo(
      description: '${state.loadedUser[index].description}',
),

您只传递描述,但没有传递 ID。这就是您在尝试更新时收到该错误的原因。

您已经可以访问要更新的待办事项,因此您可以直接传递该待办事项,而不是创建新的待办事项。使用此代码路由到EditTodoScreen

Navigator.push(
      context,
      MaterialPageRoute(
        builder: (context) => EditTodoScreen(
          todo: state.loadedUser[index],
        ),
      ),
    );

【讨论】:

  • 当我更改路由时,数据仍然没有更新,请问现在问题可能出在 EditTodoScreen 本身吗?是在我点击更新按钮的那一刻?
  • @MaxZubko 是否仍然给出无效参数警告?
  • 是的,和以前一样的错误。在 todo_list 中更改为您编写的内容(传递 id),但仍然是一个错误
  • @MaxZubko 很有趣。从我所见,似乎一切都应该没问题。在 updateTodo 方法 print("${todo.id}"); 的开头添加一个 print 语句,看看它是否为空。然后继续返回,直到找到您无法访问 id 的位置。因为在您的TodoList 中,您正在使用state.loadedUser[index].id 进行删除,并且您在问题中声明删除有效。因此,无论问题是什么,都应该进一步解决。
  • @MaxZubko 这也是您要添加到 bloc 的事件:UpdateTodos(todo, _controller.text)。但是UpdateTodos 事件只有Todo 类的待办事项。构造函数没有第二个参数。还有UpdateTodos吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多