Прежде всего, конечно, вы можете видеть,Официальная ссылка на перевод документа
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