状态管理
一. Provider
是对 InheritedWidget组件的上层封装 需要依赖于context上下文 更多详细
创建model类可以有多个属性,一个app可以有多个model类来存储数据
model类必须要继承ChangeNotifier类,否则无法刷新数据
model管理的状态,内部只有get方法,修改他的值是通过单独的方法进行修改的,在修改后要调用notifyListeners方法
model创建
import 'package:flutter/material.dart';
class Counter with ChangeNotifier {
int _count;
Counter(this._count);
void add() {
_count++;
notifyListeners();
}
get count => _count;
}
需要混入ChangeNotifier
写一个增加的方法,然后需要调用notifyListeners();这个方法是通知用到Counter对象的widget刷新用的
导入(注入)model
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(1),
child: MyApp(),
));
}
还有以下几个方法
Provider,ListenableProvider,ValueListenableProvider,StreamProvider,
如果是多个Provider
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: UserInfo('','')),
ChangeNotifierProvider.value(value: PageOne('','')),
],
child: Consumer2<UserInfo,PageOne>(builder: (context, login,user, _) {})
)
获取值或改变Provider
需要导入对应model
获取
Text("${Provider.of<Counter>(context).count}")
改变
Provider.of<Counter>(context).add();
Provider.of(context).count取值,Provider.of(context)相当于Provider去查找它管理的Counter(1)
用Provider.of(context).add();调用Counter()中的add()方法改变值
二. GetX
https://pub.dev/packages/get
优势点:
GetX 因为不需要上下文,突破了InheritedWidget的限制,我们可以在全局和模块间共享状态
AJAX数据请求到更新UI层
主要功能
- 状态管理
分别有两个状态管理器(GetBuilder)和响应式状态管理器(GetX)
响应式状态管理器
申明
var num = 0;
监听 num
var num = 0.obs;
UI层显示更新
Obx(() => Text(“${controller.num}”));
- 路由管理
不想要上下文的情况下使用
在main.dart文件下把MaterialApp替换变成GetMaterialApp
GetMaterialApp( // Before: MaterialApp(
home: MyHome(),
)
路由跳转
1.导航到新页面
Get.to(NextScreen());
2.用别名导航到新页面
Get.toNamed('/details');
3.要关闭snackbars, dialogs, bottomsheets或任何你通常会用Navigator.pop(context)关闭的东西。
Get.back();
4.进入下一个页面,但没有返回上一个页面的选项(用于闪屏页,登录页面等)。
Get.off(NextScreen());
5.进入下一个页面并取消之前的所有路由(在购物车、投票和测试中很有用)。
Get.offAll(NextScreen());
以上都不需要context上下文
- 依赖管理
Get有一个简单而强大的依赖管理器,它允许你只用1行代码就能检索到与你的Bloc或Controller相同的类,无需Provider context,无需inheritedWidget。
Controller controller = Get.put(Controller()); // 而不是 Controller controller = Controller(); 主任依赖
使用获取依赖
Controller controller = Get.find();
更多API移步 https://pub.flutter-io.cn/packages/get
项目示例
首先需要一个控制器
class nController extends GetxController {
int _counter = 0;
int get counter => _counter;
void increment() {
_counter++;
update();
}
}
UI 层显示数字变化以及控制数字
class nPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('nPage--build');
return GetBuilder<nController>(
init: nController(), //初始化
builder: (controller) {
return Scaffold(
appBar: AppBar(title: Text('数字变化..')),
body: Center(
child: Text(controller.counter.toString()),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
controller.increment();
},
child: Icon(Icons.add),
),
);
});
}
}
通过GetBuilder对 Widget 包裹了页面,在 init初始化nController,然后每次点击,都会更新builder对应的 Widget ,GetxController通过update()更新GetBuilder。
注:可以局部更新某个组件
以上代码改造
class nPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('nPage--build');
return Scaffold(
appBar: AppBar(title: Text('数字变化..')),
body: Center(
child: GetBuilder<nController>(
init: nController(),
builder: (controller) {
return Text(controller.counter.toString());
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
controller.increment();
},
child: Icon(Icons.add),
),
);
}
}
以上情况在按钮事件会找不到controller(因为作用域的关于),此时GetX就发会了作用
Get.find<nController>().increment();
GetxController生命周期
@override
void onInit() {
super.onInit();
print('nController--onInit');
}
@override
void onReady() {
super.onReady();
print('nController--onReady');
}
@override
void onClose() {
super.onClose();
print('nController--onClose');
}
局部刷新
只需要在GetBuilder对应的Controller里面添加id
update(['id值']);
响应式刷新
以上是通过Controller以流的方式发送数据,而GetX提供了.obs后缀形式更新某个小部件
var nmu = 0.obs;
监听
Obx (() => Text (controller.num));
.obs就实现了一个被观察者
.obs就实现了一个被观察者,类型是 RxInt。对应的小部件也不再是GetBuilder了,而是下面两种
final nmb1 = 0.obs;
final nmb2 = 0.obs;
GetX<nController>(
builder: (_) {
print("nmb1 rebuild");
return Text(
'${_.nmb1}',
style: TextStyle(fontWeight: FontWeight.bold),
);
},
),
Obx(() => Text(
'${Get.find<nController>().nmb2}',
style: TextStyle(fontWeight: FontWeight.bold),
)),
以上是同一个页面兄弟组件跨组件使用
跨路由
在one路由get.put oneController
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:fluttergetx/controller/OneController.dart';
class OnePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
OneController controller = Get.put(OneController());
return Scaffold(
appBar: AppBar(
title: Text("第一个页面"),
centerTitle: true,
),
body: Container(
width: double.infinity,
child: Column(
children: [
Text('第一个页面'),
ListTile(
onTap: () {
Get.toNamed('/twoPage');
},
title: Text('第二个页面'),
),
],
)
)
);
}
}
在two路由get.find oneController
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:fluttergetx/controller/OneController.dart';
class TwoPage extends StatelessWidget {
var ages = Get.find<OneController>().show();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("第二个页面"),
centerTitle: true,
),
body: Container(
width: double.infinity,
child: Column(
children: [
Text('第二个页面'),
Text('第一个页面过来的值:${ages}'),
RaisedButton(
color: Colors.blue,
child: Text('打印OneController的值',style: TextStyle(color: Colors.white),),
// 设置按钮圆角
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
onPressed: () {
print(Get.find<OneController>().show());
}
),
],
)
)
);
}
}
GetBuilder vs GetX vs Obx
项目结构