Понимание и использование поставщика управления состоянием Flutter

Flutter

Прежде всего, конечно, вы можете видеть,Официальная ссылка на перевод документа

1. Зачем нужен статус управления провайдером?

Изменение данных, обмен данными, нужен провайдер

  • Код флаттера, это响应式/声明式из. Предыдущий код Android/iOS, да命令式из.
  • 响应式Код в основном должен быть状态管理, также можно понимать как数据共享.
  • 界面、数据是变化的,就需要管理的,Простой的直接在StatefulWidget进行管理就好,复杂的就是用Provider之类来管理.

Примеры простых и сложных данных

Как просто изменить данные? - например, текущая страница в компоненте PageView, текущий прогресс в сложной анимации, текущая выбранная вкладка в BottomNavigationBar. Они находятся в дереве виджетов, и другим частям виджета не требуется доступ к этому состоянию. Нет необходимости десериализовать это состояние, и это состояние не изменяется сложным образом.

Какими изменениями данных должен управлять Privider?举例子,比如,用户选项、登录信息、一个社交应用中的通知、一个电商应用中的购物车、一个新闻应用中的文章已读/未读状态.

.
.

Управление состоянием Flutter имеетRedux,Rx,hooks,ScopedModel, а такжеProviderи т. д., гдеProviderофициально рекомендуется.

Если вы не знаете ничего другого, это определенно официальная рекомендация.

Во-вторых, использование Provider

Что ж, провайдер официально рекомендуется. Если вы незнакомы, вы можете сначала прочитать эти два.

Официальная статья провайдера

Управляйте состоянием приложения Flutter с помощью Provider


2.1 Используйте шаги

Представить провайдера

dependencies:
  provider: ^3.1.0

Использование провайдера можно просто понять как 3 шага:

  • Создайте общий класс, наследуемый от ChangeNotifier
  • установить данные
  • Есть два способа получить данные, а именно Provider.of(context) и Consumer.

Это очень просто~

.
.
.

2.2 Простейший пример метода Provider.of(context)

Следующий код:

  • Создайте общий класс, добавьте метод для увеличения данных и обновления при вызове.
  • данные вызова
  • сборка вызывается снова, обновите пользовательский интерфейс

import 'package:flutter/material.dart';

import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 创建 Widget 持有 CounterNotifier 数据
    return ChangeNotifierProvider.value(
      value: CounterNotifier(),
      child: MaterialApp(
        title: 'Privoder Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: ProvidePage(title: 'Provider 测试页面'),
      ),
    );
  }
}

class ProvidePage extends StatelessWidget {
  final String title;

  ProvidePage({Key key, this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {

    // 获取 CounterNotifier 数据 (最简单的方式)
    final counter = Provider.of<CounterNotifier>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '按下按钮,使数字增长:',
            ),
            Text(
              '${counter.count}',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          counter.increment();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}


//  核心:继承自ChangeNotifier
// 这种文件本来应该单独放在一个类文件连的
class CounterNotifier with ChangeNotifier {
  int _count = 0;
  int get count => _count;

  increment() {
    _count++;
    // 核心方法,通知刷新UI,调用build方法
    notifyListeners();
  }
}

.
.

Эффект:

Уведомление

  • Используйте Provider.of для повторного вызова сборки в виджете каждый раз, когда notifyListeners вызывается в ChangeNotifier.

Наверное так. Кто бы что ни говорил, просто setState напрямую. Нет, это точно не то же самое, setState слишком негибок.

.
.
.

2.3 Пример потребительского метода

Пример: установите 1 значение на странице 1, затем отобразите его на странице 2 (не спрашивайте, почему вы не используете Navigator напрямую, демо-демо, просто для демо)

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

main() {
  runApp(ChangeNotifierProvider<CounterNotifier>.value(
    value: CounterNotifier(),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MultiProvider(
      providers: [
        Provider.value(value: 36),
        ChangeNotifierProvider.value(value: CounterNotifier())
      ],
      child: MaterialApp(
        title: 'Privoder Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: Page1(),
      ),
    );

 }
}

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //获取文字大小
    final size = Provider.of<int>(context).toDouble();
    // 获取计数
    final counter = Provider.of<CounterNotifier>(context);
    // 调用 build 时输出
    print('rebuild page 1');
    return Scaffold(
      appBar: AppBar(
        title: Text('Page1'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // 显示计数
            Text(
              'Current count: ${counter.count}',
              // 设置文字大小
              style: TextStyle(
                fontSize: size,
              ),
            ),
            SizedBox(
              height: 50,
            ),
            // 跳转 Page2
            RaisedButton(
              onPressed: () => Navigator.of(context).push(
                MaterialPageRoute(builder: (context) => Page2()),
              ),
              child: Text('Next'),
            ),
          ],
        ),
      ),
    );
  }
}


class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    print('rebuild page 2');
    return Scaffold(
      appBar: AppBar(
        title: Text('Page2'),
      ),
      body: Center(
        child: Consumer2<CounterNotifier, int>(
            builder: (context, counter, size, _) {
              print('rebuild page 2 refresh count');

              return Column(
                mainAxisSize: MainAxisSize.min,
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text(
                    'You have pushed the button this many times:',
                  ),
                  Text(
                    '${counter.count}',
                    style: TextStyle(
                      fontSize: size.toDouble(),
                    ),
                  ),
                ],
              );
            }),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 不需要监听改变(listen: false 不会重新调用build)
          Provider.of<CounterNotifier>(context, listen: false).increment();
        },
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}


class CounterNotifier with ChangeNotifier {
  int _count = 0;

  int get count => _count;

  increment() {
    _count++;
    notifyListeners();
  }
}


.

Уведомление

  • 1. На странице 2 используется Consumer
  • 2. Если прослушивание Provider.of ложно, сборка больше не будет вызываться.

.
Страница 2 устанавливает значение, при возврате на страницу 1 страница 1 отображает значение страницы 2

.
.

.

В сравнении
  • Триггер (Provider.of): если вам просто нужно получить модель данных,不需要监听变化(Например, нажав кнопку), рекомендуется Provider.OF (контекст, прослушивание: false) для получения модели данных.
  • Слушатель (рекомендуется потребитель): рекомендуется потребитель.

.
.

END

Ссылаться на:Flutter запускает сухую серию — провайдер управления состоянием3