GetX功能介绍
- 依赖注入
- GetX是通过依赖注入的方式,存储相应的XxxGetxController;已经脱离了InheritedWidget那一套玩法,自己手动去管理这些实例,使用场景被大大拓展
- 简单的思路,却能产生深远的影响:优雅的跨页面功能便是基于这种设计而实现的、获取实例无需BuildContext、GetBuilder自动化的处理及其减少了入参等等
- 跨页面交互
- 这绝对是GetX的一个优点!对于复杂的生产环境,跨页面交互的场景,实在太常见了,GetX的跨页面交互,几乎和fish_redux一样简单。
- 路由管理
- 是的,getx内部实现了路由管理,而且用起来,那叫一个简单!bloc没实现路由管理,这让我不得不去找一个star量高的路由管理框架,就选择了fluro,但是让我不得不说,这个fluro用起来真的叫一个折磨人,每次新建一个页面,最让我抗拒的就是去写fluro路由代码,横跨几个文件来回写,真是肝疼
- GetX实现了动态路由传参,也就是说直接在命名路由上拼参数,然后能拿到这些拼在路由上的参数,也就是说用flutter写H5,直接能通过Url传值(fluro也能做到)
- 实现了全局BuildContext
- 国际化,主题实现。
使用
引用
# getx 状态管理框架 https://pub.flutter-io.cn/packages/get
# 非空安全最后一个版本(flutter 2.0之前版本)
get: ^3.26.0
# 空安全版本 最新版本请查看 https://pub.flutter-io.cn/packages/get
get: ^4.3.8
- Github:jonataslaw/getx
Pub:get
程序入口
只需要将MaterialApp改成GetMaterialApp即可 ```dart void main() { runApp(MyApp()); }
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return GetMaterialApp( home: CounterGetPage(), ); } }
<a name="gWQW7"></a>
### 插件
**此外,为了进一步提高您的生产效率,我们还为您准备了一些插件**
- **getx_template**:一键生成每个页面必需的文件夹、文件、模板代码等等
- [Android Studio/Intellij插件](https://plugins.jetbrains.com/plugin/15919-getx)
- **GetX Snippets**:输入少量字母,自动提示选择后,可生成常用的模板代码
- [Android Studio/Intellij扩展](https://plugins.jetbrains.com/plugin/14975-getx-snippets)
- [VSCode扩展](https://marketplace.visualstudio.com/items?itemName=get-snippets.get-snippets)
<a name="Caanv"></a>
### 计数器程序
> 实现一个计数器程序来看下GetX如何将逻辑层和界面层解耦。
1. 创建一个 get_x_demo 的 flutter 项目。
1. 安装 getx。
```shell
flutter pub add get
- 利用插件生成文件。
- 修改主入口 ```dart import ‘package:flutter/material.dart’; import ‘package:get/get.dart’;
import ‘counter_get/view.dart’;
void main() { runApp(const MyApp()); }
class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { return GetMaterialApp( title: ‘Flutter Demo’, theme: ThemeData(primarySwatch: Colors.blue), home: const CounterGetPage(), ); } }
5. 编写逻辑层代码
```dart
import 'package:get/get.dart';
class CounterGetLogic extends GetxController {
var count = 0.obs;
/// 自增
void increase() => ++count;
/// 自减
void remove() => --count;
}
- 编写视图层代码 ```dart import ‘package:flutter/material.dart’; import ‘package:get/get.dart’;
import ‘logic.dart’;
class CounterGetPage extends StatelessWidget { const CounterGetPage({Key? key}) : super(key: key);
@override Widget build(BuildContext context) { final logic = Get.put(CounterGetLogic()); return Scaffold( appBar: AppBar( title: const Text(“GetX Count”), ), body: Center( child: Obx(() { return Text( logic.count.value.toString(), style: const TextStyle(fontSize: 24), ); }), ), floatingActionButton: Column( mainAxisSize: MainAxisSize.min, children: [ FloatingActionButton( heroTag: “add”, onPressed: logic.increase, child: const Icon(Icons.add), ), const SizedBox(height: 10), FloatingActionButton( heroTag: “sub”, onPressed: logic.remove, backgroundColor: Colors.red, child: const Icon(Icons.remove), ) ], ), ); } }
7. 运行程序

<a name="uBWp1"></a>
## 状态管理
<a name="L6Nsl"></a>
### 响应式状态管理
> 上面的实例中,我们看到两个关键字「obs」和「obx」,配合使用即可。
<a name="XC8wi"></a>
#### 基本数据类型
> 定义一个需要状态管理的变量。obs是响应式状态管理,自动完成数据更新。
Obx()方法刷新的条件
- 只有当响应式变量的值发生变化时,才会会执行刷新操作,当某个变量初始值为:“test”,再赋值为:“test”,并不会执行刷新操作
- 当你定义了一个响应式变量,该响应式变量改变时,包裹该响应式变量的Obx()方法才会执行刷新操作,其它的未包裹该响应式变量的Obx()方法并不会执行刷新操作。
<a name="qSEuS"></a>
#### 基于类的使用
```dart
import 'package:get/get.dart';
import 'package:get_x_demo/user_obs/user.dart';
import 'dart:math';
class UserObsLogic extends GetxController {
final _names = ["JsonYe", "LiuLi", "Luna", "Tomer"];
final user = User().obs;
@override
void onInit() {
super.onInit();
updateUser();
}
void updateUser() {
User _user = User(
name: _names[Random().nextInt(3)],
age: 30 + Random().nextInt(50),
sex: Random().nextBool());
user.update((val) {
val?.name = _user.name;
val?.age = _user.age;
val?.sex = _user.sex;
});
}
}
class User {
String? name;
int? age;
bool? sex;
User({this.name, this.age, this.sex});
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'logic.dart';
class UserObsPage extends StatelessWidget {
const UserObsPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final logic = Get.put(UserObsLogic());
return Scaffold(
appBar: AppBar(
title: const Text("Object obs"),
),
body: Center(
child: Obx(() {
return DefaultTextStyle(
style: const TextStyle(color: Colors.black, fontSize: 30),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("${logic.user.value.name}"),
Text("${logic.user.value.age}"),
Text("${logic.user().sex}"),
],
),
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: logic.updateUser,
child: const Icon(Icons.sync),
),
);
}
}
简单状态管理
通过GetBuilder组件构建,update()方法手动更新。
import 'dart:math';
import 'package:get/get.dart';
class BasicGetLogic extends GetxController {
final _names = ["JsonYe", "LiuLi", "Luna", "Tomer"];
String? name;
int? age;
bool? sex;
@override
void onInit() {
super.onInit();
updateUser();
}
void updateUser() {
name = _names[Random().nextInt(3)];
age = 30 + Random().nextInt(50);
sex = Random().nextBool();
update();
}
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'logic.dart';
class BasicGetPage extends StatelessWidget {
const BasicGetPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final logic = Get.put(BasicGetLogic());
return Scaffold(
appBar: AppBar(
title: const Text("Basic GetX"),
),
body: Center(
child: GetBuilder<BasicGetLogic>(
builder: (_logic) {
return DefaultTextStyle(
style: const TextStyle(color: Colors.black, fontSize: 30),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text("${_logic.name}"),
Text("${_logic.age}"),
Text("${_logic.sex}"),
],
),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: logic.updateUser,
child: const Icon(Icons.sync),
),
);
}
}
Obx和GetBuilder比较
分析
- Obx是配合Rx响应式变量使用、GetBuilder是配合update使用:请注意,这完全是俩套定点刷新控件的方案
- 区别:前者响应式变量变化,Obx自动刷新;后者需要使用update手动调用刷新
- 每一个响应式变量,都需要生成对应的GetStream,占用资源大于基本数据类型,会对内存造成一定压力
GetBuilder内部实际上是对StatefulWidget的封装,所以占用资源极小
使用场景
一般来说,对于大多数场景都是可以使用响应式变量的
- 但是,在一个包含了大量对象的List,都使用响应式变量,将生成大量的GetStream,必将对内存造成较大的压力,该情况下,就要考虑使用简单状态管理了
- 总的来说:推荐GetBuilder和update配合的写法
- GetBuilder内置回收GetxController的功能,能避免一些无法自动回收GetxController的坑爹问题
- 使用GetBuilder的自动回收:GetBuilder需要设置assignId: true;或使用插件一键Wrap Widget:GetBuilder(Auto Dispose)
- 使用Obx,相关变量定义初始化以及实体更新和常规写法不同,会对初次接触该框架的人,造成很大的困扰
- getx插件现已支持一键Wrap Widget生成GetBuilder,可以一定程度上提升你的开发效率
- GetBuilder内置回收GetxController的功能,能避免一些无法自动回收GetxController的坑爹问题
跨页面交互
页面1
import 'package:get/get.dart';
import 'package:get_x_demo/more_page_get/page_two_get/view.dart';
class PageOneGetLogic extends GetxController {
var count = 0;
void toTwoPage() {
Get.to(const PageTwoGetPage());
}
void increase() {
count = ++count;
update();
}
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'logic.dart';
class PageOneGetPage extends StatelessWidget {
const PageOneGetPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final logic = Get.put(PageOneGetLogic());
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: const Text('One Page')),
floatingActionButton: FloatingActionButton(
onPressed: logic.toTwoPage,
child: const Icon(Icons.arrow_forward_outlined),
),
body: Center(
child: GetBuilder<PageOneGetLogic>(
builder: (logic) {
return Text(
'Two点击了 ${logic.count} 次',
style: const TextStyle(fontSize: 30.0),
);
},
),
),
);
}
}
页面2
import 'package:get/get.dart';
import 'package:get_x_demo/more_page_get/page_one_get/logic.dart';
class PageTwoGetLogic extends GetxController {
final oneLogic = Get.put(PageOneGetLogic());
var count = 0;
@override
void onReady() {
count = oneLogic.count;
update();
super.onReady();
}
void increase() {
oneLogic.increase();
count = oneLogic.count;
update();
}
}
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get_x_demo/more_page_get/page_one_get/logic.dart';
import 'logic.dart';
class PageTwoGetPage extends StatelessWidget {
const PageTwoGetPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final twoLogic = Get.put(PageTwoGetLogic());
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: const Text('Two Page')),
floatingActionButton: FloatingActionButton(
onPressed: twoLogic.increase,
child: const Icon(Icons.add),
),
body: Center(
child: GetBuilder<PageTwoGetLogic>(
builder: (logic) {
return Text(
'点击了 ${logic.count} 次',
style: const TextStyle(fontSize: 30.0),
);
},
),
),
);
}
}
状态分离
划分三个结构:state(状态层),logic(逻辑层),view(界面层)
State
class CountStateGetState {
late int count;
CountStateGetState() {
count = 0;
}
}
logic
import 'package:get/get.dart';
import 'state.dart';
class CountStateGetLogic extends GetxController {
final CountStateGetState state = CountStateGetState();
void increase() {
state.count = ++state.count;
update();
}
void remove() {
state.count = --state.count;
update();
}
}
view
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'logic.dart';
class CountStateGetPage extends StatelessWidget {
const CountStateGetPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final logic = Get.put(CountStateGetLogic());
final state = Get.find<CountStateGetLogic>().state;
return Scaffold(
appBar: AppBar(
title: const Text("Count State Demo"),
),
body: Center(
child: GetBuilder<CountStateGetLogic>(builder: (_) {
return Text(
state.count.toString(),
style: const TextStyle(fontSize: 30),
);
}),
),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
heroTag: "add",
onPressed: logic.increase,
child: const Icon(Icons.add),
),
const SizedBox(height: 10),
FloatingActionButton(
heroTag: "sub",
onPressed: logic.remove,
backgroundColor: Colors.red,
child: const Icon(Icons.remove),
)
],
),
);
}
}
- logic只专注于触发事件交互,state只专注数据。
Binding使用
可以统一管理复杂模块的多个GetXController。需要结合getx路由进行使用。
路由
import 'package:get/get.dart';
import 'package:get_x_demo/binding_demo/binding_one_page/binding.dart';
import 'package:get_x_demo/binding_demo/binding_one_page/view.dart';
import 'package:get_x_demo/binding_demo/binding_two_page/binding.dart';
import 'package:get_x_demo/binding_demo/binding_two_page/view.dart';
class RouteConfig {
static const String testOne = "/testOne";
static const String testTwo = "/testTwo";
static final List<GetPage> getPages = [
GetPage(
name: testOne,
page: () => const BindingOnePage(),
binding: BindingOnePageBinding(),
),
GetPage(
name: testTwo,
page: () => const BindingTwoPage(),
binding: BindingTwoPageBinding(),
),
];
}
Page One
- Logic ```dart import ‘package:get/get.dart’; import ‘package:get_x_demo/binding_demo/route_config.dart’;
class BindingOnePageLogic extends GetxController { void toTwoPage() { Get.toNamed(RouteConfig.testTwo); } }
- Binding
```dart
import 'package:get/get.dart';
import 'logic.dart';
class BindingOnePageBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut(() => BindingOnePageLogic());
}
}
- View ```dart import ‘package:flutter/material.dart’; import ‘package:get/get.dart’;
import ‘logic.dart’;
class BindingOnePage extends StatelessWidget { const BindingOnePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final logic = Get.find
<a name="Wsz84"></a>
### Page Two
- Logic
```dart
import 'package:get/get.dart';
class BindingTwoPageLogic extends GetxController {
int count = 0;
void increase() {
count++;
update();
}
void remove() {
count--;
update();
}
}
- Binding ```dart import ‘package:get/get.dart’;
import ‘logic.dart’;
class BindingTwoPageBinding extends Bindings { @override void dependencies() { Get.lazyPut(() => BindingTwoPageLogic()); } }
- View
```dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'logic.dart';
class BindingTwoPage extends StatelessWidget {
const BindingTwoPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final logic = Get.find<BindingTwoPageLogic>();
return Scaffold(
appBar: AppBar(
title: const Text("Binding Two Page"),
),
body: Center(
child: GetBuilder<BindingTwoPageLogic>(
assignId: true,
builder: (logic) {
return Text(
logic.count.toString(),
);
},
),
),
floatingActionButton: Column(
mainAxisSize: MainAxisSize.min,
children: [
FloatingActionButton(
heroTag: "add",
onPressed: logic.increase,
child: const Icon(Icons.add),
),
const SizedBox(height: 10),
FloatingActionButton(
heroTag: "sub",
onPressed: logic.remove,
backgroundColor: Colors.red,
child: const Icon(Icons.remove),
)
],
),
);
}
}