状态-Getx
原文地址 zhuanlan.zhihu.com
状态-Getx
GetxController 生命周期
整个生命周期我们能够接入的方法就三个:
- onInit:初始化 Controller,例如一些成员属性的初始化;
- onReady:就绪后的业务处理,如异步操作、导航进入的参数处理等;
- onClose:释放资源,避免内存泄露,同时也可以进行数据持久化。
GetBuilder 是一个 Widget 组件, 在 GetX 的状态管理中,GetBuilder 的主要作用是结合 GetxController 实现界面数据的更新。当调用 GetxController 的 update 方法时,GetBuilder 包裹的 Widget 就会刷新从而实现界面数据的更新。
局部更新
多种状态可以分别更新,不需要为每个状态创建一个类。
再添加一个变量:
- int _counter = 0;
- int get counter => _counter;
- String _name = "Lili";
- String get firstName => _name;
- void increment() {
- _counter++;
- _name = WordPair.random().asPascalCase;
- update(['counter']);
- }
- void changeName() {
- _counter++;
- _name = WordPair.random().asPascalCase;
- update(['name']);
- }
两个方法分别改变两个变量,但是注意update(['counter']里添加了 id 数组,这样就只更新这个 id 对应的GetBuilder:
- GetBuilder
( - id: 'counter',
- builder: (ctl) => Text(ctl.counter.toString()),
- ),
- SizedBox(
- height: 50,
- ),
- GetBuilder
( - id: 'name',
- builder: (ctl) => Text(ctl.firstName),
- ),
响应式刷新
我们都用过 StreamControllers ,然后以流的方式发送数据。在 GetX 可以实现同样的功能,并且实现起来只有几个单词,不需要为每个观察的对象创建一个 StreamController ,也不需要创建 StreamBuilder。
var name = '新衣';
下面简单的一个后缀就可以把一个变量变得可观察,变量每次改变的时候,使用它的小部件就会被更新:
var name = '新衣'.obs;
就这么简单,这个变量已经是响应式的了。然后通过 Obx 或者 GetX 包裹并使用响应式变量的控件,在变量改变的时候就会被更新:
Obx (() => Text (controller.name));
下面写个计算器的例子:
- final count1 = 0.obs;
- final count2 = 0.obs;
.obs就实现了一个被观察者,他们不再是 int 类型,而是 RxInt 类型。对应的小部件也不再是GetBuilder了,而是下面两种:
- GetX
( - builder: (_) {
- print("count1 rebuild");
- return Text(
- '${_.count1}',
- style: TextStyle(fontWeight: FontWeight.bold),
- );
- },
- ),
- Obx(() => Text(
- '${Get.find
().count2}', - style: TextStyle(fontWeight: FontWeight.bold),
- )),
因为是响应式,不再需要update,每次更改值,都自动刷新。但是更神奇的是,他们的运算和也是响应式的:
int get sum => count1.value + count2.value;
只要更新count1或者count2使用sum的小部件也会更改:
- Obx(() => Text(
- '${Get.find
().sum}', - style: TextStyle(fontWeight: FontWeight.bold),
- )),
setState
当调用setState后,所在Widget会进行重新渲染,这样便实现了页面上显示数据的更新。
下方代码中,点击按钮是否会触发页面上的数字变化?
class XXXState extends State<TestPage> {
var click = 0;
Widget w;
@override
void initState() {
super.initState();
w = Column(
children: <Widget>[
Text("${click}"),
RaisedButton(
child: Text("点击"),
onPressed: () {
click++;
setState(() {});
},
),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: w,
);
}
}
...
解答:不会变化,因为w变量中的组件,并没有重新实例化,所有w的状态一直都保持不变,组件一直保存在变量w中。
点击按钮确实会使当前组件重新渲染、会重新调用build,但是其中的子组件w,并没有重新实例化,其中的状态也没有发生任何改变