每次屏幕重新加载时,Flutter listview 都会不断重复

问题描述 投票:0回答:3

每次重新打开页面时,我创建的列表视图都会不断重复。我在状态小部件中调用了一种方法来调用 Sqflite 包中的列表,但我希望该方法仅被调用一次。我尝试使用 dispose,但显然,无法处理方法(?) 代码片段如下,谢谢

 class TodoList extends StatefulWidget {
  const TodoList({Key? key}) : super(key: key);

  @override
  State<TodoList> createState() => _TodoListState();
}

class _TodoListState extends State<TodoList> {

  getAllTodos() async {
    
    List<TodoModel> _todoList = await TodoDatabase.instance.queryAlltodos();

    _todoList.forEach((todo) {
      var todoModel = TodoModel(
          title: todo.title,
          description: todo.description,
          created: todo.created,
          isChecked: todo.isChecked);
      context.read<TodoProvider>().todoitem.add(todoModel);
      
    });
  }

  @override
  void initState() {
    super.initState();
    getAllTodos();
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    final theme = Theme.of(context);
    return FutureBuilder<List<TodoModel>>(
      future: TodoDatabase.instance.queryAlltodos(),
      builder: (BuildContext context, AsyncSnapshot<List<TodoModel>> snapshot) {
        if(!snapshot.hasData) {
          return const Center(child: CircularProgressIndicator(color: Colors.amber),);
        } return
        Padding(
              padding: const EdgeInsets.all(10),
              child: Consumer<TodoProvider>(
                  builder: (context, value, child) => (value.newTodo.isEmpty)
                      ? const Center(child: Text('No Todos'))
                      : ListView.separated(
                          itemCount: value.newTodo.length,
                          physics: const BouncingScrollPhysics(),
                          separatorBuilder: (context, index) => SizedBox(
                                height: size.height * 0.01,
                              ),
                          itemBuilder: (_, i) =>  Slidable(
                                key: ValueKey(i),
                                startActionPane: ActionPane(
                                  motion: StretchMotion(),
                                  children: [
                                    SlidableAction(
                                      backgroundColor: Colors.green,
                                      foregroundColor: Colors.black,
                                      icon: Icons.edit,
                                      label: 'Edit',
                                      onPressed: (context) async {
                                        TodoModel todo = value.newTodo[i];
                                        editTodo(context, todo);
                                        // Navigator.of(context).pushNamed(
                                        //   EditScreen.editscreen,
                                        //   arguments: todoData
                                        // );
                                        showSnackBar(
                                            context, 'Edit ${todo.title}?');
                                      },
                                    )
                                  ],
                                ),
                                endActionPane: ActionPane(
                                  motion: ScrollMotion(),
                                  children: [
                                    SlidableAction(
                                        backgroundColor: Colors.red,
                                        foregroundColor: Colors.black,
                                        spacing: 0,
                                        icon: Icons.delete,
                                        label: 'delete',
                                        onPressed: (context) async {
                                          showDialog(
                                              context: context,
                                              builder: (context) {
                                                return AlertDialog(
                                                    shape: RoundedRectangleBorder(
                                                      borderRadius:
                                                          BorderRadius.circular(
                                                              20),
                                                    ),
                                                    title:
                                                        const Text('Delete this TODO',style: TextStyle(color: Colors.amber)),
                                                    content:
                                                        const Text('Are you Sure?'),
                                                    actions: [
                                                      TextButton(
                                                        child: const Text('No',style: TextStyle(color: Colors.amber)),
                                                        onPressed: () {
                                                          Navigator.pop(context);
                                                        },
                                                      ),
                                                      TextButton(
                                                          child: const Text('Yes',style: TextStyle(color: Colors.amber)),
                                                          onPressed: () async {
                                                            TodoModel todo =
                                                                value.newTodo[i];
                                                            String result =
                                                                await context
                                                                    .read<
                                                                        TodoProvider>()
                                                                    .deleteToDo(
                                                                        todo);
                                                            if (result != 'OK!') {
                                                              return showSnackBar(
                                                                  context,
                                                                  result);
                                                            } else {
                                                              showSnackBar(
                                                                  context,
                                                                  'Deleted');
                                                              Navigator.pop(
                                                                  context);
                                                            }
                                                          })
                                                    ]);
                                              });
                                        })
                                  ],
                                ),
                                child: InkWell(
                                  onTap: () {},
                                  child: ListTile(
                                    tileColor: theme.primaryColorLight,
                                    shape: RoundedRectangleBorder(
                                      borderRadius: BorderRadius.circular(20),
                                    ),
                                    leading: Checkbox(
                                      shape: RoundedRectangleBorder(
                                          borderRadius: BorderRadius.circular(3)),
                                      value: value.newTodo[i].isChecked,
                                      activeColor: theme.primaryColorDark,
                                      checkColor: theme.primaryColorLight,
                                      onChanged: (_) async {
                                        // return setState(() {  // this works too
                                        //   todo.isChecked = value;
                                        // });
                                        TodoModel todo = value.todoitem[i];
    
                                        await context
                                            .read<TodoProvider>()
                                            .updateTodo(todo);
                                      },
                                    ),
                                    title: Text(value.newTodo[i].title),
                                    subtitle: Text(value.newTodo[i].description),
                                  ),
                                ),
                              ))),
            );
  });
  }
}

void editTodo(BuildContext context, TodoModel todo) {
  Navigator.of(context).push(
    MaterialPageRoute(
      builder: (context) => EditScreen(todo: todo),
    ),
  );
}
flutter dart flutter-layout sqflite
3个回答
0
投票

重新加载时先清除列表。这是例子

if(listName!=null) {
  listName.clear();
}

0
投票

试试这个:

getAllTodos() async {
    List<TodoModel> _todoList = [];
    _todoList = await TodoDatabase.instance.queryAlltodos();

    _todoList.forEach((todo) {
      var todoModel = TodoModel(
          title: todo.title,
          description: todo.description,
          created: todo.created,
          isChecked: todo.isChecked);
      context.read<TodoProvider>().todoitem.add(todoModel);
      
    });
  }

0
投票

你的问题似乎出在代码的内层。

我也遇到了类似的问题,数据重复。请看下面的截图:

我的问题在于提供者(Riverpod)对存储库的调用。重建屏幕时我一次又一次地拨打电话(我不确定“重建”是否是一个好的做法)。

我在该方法的使用中添加了一个条件,这解决了问题。

查看

// ADDED LINE
评论在哪里。

final pruebasListProvider =
    StateNotifierProvider<PruebasListNotifier, List<Prueba>>((ref) {
  final getPruebasList = ref.watch(pruebasRepositoryProvider).getPruebasList;

  return PruebasListNotifier(fetchPruebasList: getPruebasList);
});

typedef GetPruebasListCallback = Future<List<Prueba>> Function();

class PruebasListNotifier extends StateNotifier<List<Prueba>> {
  bool isLoading = false;
  bool isLoaded = false; // ADDED LINE
  GetPruebasListCallback fetchPruebasList;

  PruebasListNotifier({required this.fetchPruebasList}) : super([]);

  Future<void> loadPruebasList() async {
    if (isLoading) return;
    isLoading = true; 

    if (isLoaded) return;  // ADDED LINE
    final List<Prueba> pruebas = await fetchPruebasList();

    state = [...state, ...pruebas];

    await Future.delayed(const Duration(milliseconds: 300));
    isLoading = false;
    isLoaded = true;  // ADDED LINE
  }
}

已解决:

我想说你在这一行也有类似的问题:

future: TodoDatabase.instance.queryAlltodos(),

但这是我最好的猜测。我看不到该方法的内部。

© www.soinside.com 2019 - 2024. All rights reserved.