Сохранение данных поставщика на нескольких страницах не работает

Я использую Provider в своем приложении flutter, и когда я перехожу на новую страницу, данные, предоставленные Provider на странице 1, недоступны на странице 2.

Как я понял, принцип работы Provider заключался в том, что есть центральное место, где хранятся все данные, и можно получить доступ к этим данным в любом месте приложения. Итак, в моем приложении, показанном ниже, ToDoListManager - это место, где хранятся все данные. И если я установлю данные в Page 1, тогда я смогу получить доступ к этим данным в Page 2, и наоборот.

Если это неверно, то какая часть не так? И почему в моем приложении не работает?

Вот код

Страница 1

class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      builder: (context) => ToDoListManager(),
      child: Scaffold(
        appBar: AppBar(
          title: Text('Cool Project'),
        ),
        body:e ToDoList(),
      ),
    );
  }
}

class ToDoList extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final toDoListManager = Provider.of<ToDoListManager>(context);

    return ListView.builder(
      itemCount: toDoListManager.toDoList.length,
      itemBuilder: (context, index) {
        return GestureDetector(
          onTap: () {
            Navigator.push(context,
                MaterialPageRoute(builder: (context) => Details(index)));
          },
          child: Text(toDoListManager.toDoList[index]),
        );
      },
    );
  }
}

Страница 2

class Details extends StatelessWidget {
  final int index;

  Details(this.index);

  @override
  build(BuildContext context) {
    return ChangeNotifierProvider(
      builder: (context) => ToDoListManager(),
      child: Scaffold(
          appBar: AppBar(
            title: Text('Details Bro'),
          ),
          body: AppBody(index)),
    );
  }
}

class AppBody extends StatelessWidget {
  final int index;

  AppBody(this.index);

  @override
  Widget build(BuildContext context) {
    final toDoListManager = Provider.of<ToDoListManager>(context);
    print(toDoListManager.toDoList);

    return Text(toDoListManager.toDoList[1]);
  }
}

ToDoListProvider

class ToDoListManager with ChangeNotifier {
  List<String> _toDoList = ['yo', 'bro'];

  List<String> get toDoList => _toDoList;

  set toDoList(List<String> newToDoList) {
    _toDoList = newToDoList;
    notifyListeners();
  }
}

person Jessica    schedule 12.09.2019    source источник
comment
Этот вопрос аналогичен простому примеру   -  person Huy Tower    schedule 21.07.2020


Ответы (1)


У вас есть 2 варианта:

  1. Поместите свой ChangeNotifierProvider над своим MaterialApp, чтобы он был доступен с любого из вас Navigator маршрутов.

  2. Оставьте свой Home виджет как есть, но при нажатии нового виджета с помощью Navigator укажите исходный менеджер.

onTap: () {
    Navigator.push(
        context,
        MaterialPageRoute(
            builder: (context) {
                return Provider<ToDoListManager>.value(
                    value: toDoListManager,
                    child: Details(index),
                );
            },
        ),
    );
},

При использовании обоих подходов вам не нужно создавать новый ChangeNotifierProvider на экране сведений.

person Martyns    schedule 13.09.2019
comment
Если использовать подход размещения ChangeNotifierProvider над MaterialApp, будет ли все приложение перезагружено при изменении значения? - person Jessica; 17.09.2019
comment
Нет, только виджеты, которые используют Provider.of ‹ToDoListManager› (контекст) или Consumer ‹ToDoListManager›. Размещение их над MaterialApp - это всего лишь вопрос объема. Если у вас есть указанное значение, которое имеет смысл внутри экрана, вы можете иметь его в определенном виджете экрана. - person Martyns; 18.09.2019
comment
Спасибо! И разница между потребителем и поставщиком заключается в том, что потребитель поддерживает изменение пользовательского интерфейса, такое как переключатель / вкладка, по сравнению с поставщиком, который будет обновлять данные и, таким образом, обновлять пользовательский интерфейс? - person Jessica; 18.09.2019
comment
Просто Provider.of перестроит вызов метода сборки, а Consumer перестроит, вызвав свой построитель свойств pub.dev / packages / provider # faq - person Martyns; 18.09.2019
comment
Спасибо, Мартинс, за объяснение! - person Jessica; 18.09.2019
comment
Думаю не надо вставлять Provider<ToDoListManager>.value() - person Huy Tower; 21.07.2020
comment
@HuyTower Вы делаете, если ваш провайдер не выше MaterialApp. В противном случае навигация создаст ветвь в дереве виджетов, где этот провайдер не существует. - person Martyns; 21.07.2020
comment
Хорошо, понятно, я думаю, что вставить MultiProvider выше MaterialApp тоже неплохо. / - person Huy Tower; 22.07.2020