GetX 是 Flutter 上的一个轻量且强大的解决方案:高性能的状态管理、智能的依赖注入和便捷的路由管理。
为什么选择 GetX?
1)将 Get 添加到pubspec.yaml
文件中。
dependencies:
get:
2)在需要用到的文件中导入。
import 'package:get/get.dart';
100多行(含注释) "计数器 "项目使用 GetX 重写只需 26 行代码(含注释)。
1) 在MaterialApp前添加 "Get",将其变成GetMaterialApp。
void () => runApp(GetMaterialApp(home: Home()));
GetMaterialApp
是 预配置的封装型 Widget,可内置路由、依赖注入、国际化等关键配置。2)创建业务逻辑类,并将所有的变量,方法和控制器放在里面。
class Controller extends GetxController{
var count = 0.obs;
increment() => count++;
}
3)创建界面,使用StatelessWidget节省一些内存。
class Home extends StatelessWidget {
@override
Widget build(context) {
// 使用Get.put()实例化你的类,使其对当下的所有子路由可用。
final Controller c = Get.put(Controller());
return Scaffold(
// 使用Obx(()=>每当改变计数时,就更新Text()。
appBar: AppBar(title: Obx(() => Text("Clicks: ${c.count}"))),
// 用一个简单的Get.to()即可代替Navigator.push那8行,无需上下文!
body: Center(child: ElevatedButton(
child: Text("Go to Other"), onPressed: () => Get.to(Other()))),
floatingActionButton:
FloatingActionButton(child: Icon(Icons.add), onPressed: c.increment));
}
}
class Other extends StatelessWidget {
// 你可以让Get找到一个正在被其他页面使用的Controller,并将它返回给你。
final Controller c = Get.find();
@override
Widget build(context){
// 访问更新后的计数变量
return Scaffold(body: Center(child: Text("${c.count}")));
}
}
Get有两个不同的状态管理器:简单的状态管理器(GetBuilder)和响应式状态管理器(GetX)。
简单的状态管理器:需手动调用update()
触发刷新。
响应式状态管理器
这就是你的计数变量。
var name = 'Jonatas Borges';
要想让它变得可观察,你只需要在它的末尾加上".obs"。
var name = 'Jonatas Borges'.obs;
而在UI中,当你想显示该值并在值变化时更新页面,只需这样做。
Obx(() => Text("${controller.name}"));
声明响应式变量的方式
使用 |
final name = RxString(''); |
使用 |
final name = Rx |
添加 |
final name = ''.obs; |
1)在MaterialApp前加上 "Get",把它变成GetMaterialApp。
void main() {
runApp(
GetMaterialApp( // Before: MaterialApp(
initialRoute: '/',
getPages: [ // 定义路由
GetPage(name: '/', page: () => MyHomePage()),
GetPage(name: '/second', page: () => Second()),
GetPage(
name: '/third',
page: () => Third(),
transition: Transition.zoom
),
],
)
);
}
2)常用方法
Get.to(NextScreen()); //导航到新页面
Get.toNamed('/second'); //用别名导航到新页面
Get.back(); //关闭页面
Get.off(NextScreen()); //进入下一个页面,但没有返回上一个页面的选项
Get.offAll(NextScreen()); //进入下一个页面并取消之前的所有路由
1)注入依赖
Controller controller = Get.put(Controller()); // 而不是 Controller controller = Controller();
调用 Get.put()、Get.lazyPut()、Get.putAsync()、Get.create() 会创建一个新的依赖项,然后将它注册到依赖管理容器中。
2)获取依赖
final controller = Get.find();
// 或者
Controller controller = Get.find();
调用Get.find()方法时,GetX会根据指定的类型从依赖管理容器中查找对应的依赖项。如果找到,就返回这个依赖项;否则抛出一个异常。
由于在 Flutter 中,有时需要在不同的组件中访问和操作同一个控制器实例。为了避免在每个组件中都写一遍 Get.find(),GetX 库提供了一个 GetView 中间件。
GetView 的主要功能是简化控制器的获取。当你创建一个继承自 GetView 的组件时,你只需要指定控制器的类型,然后就可以在组件中直接使用 controller
属性来访问控制器实例。
class CounterPage extends GetView {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(
child: Obx(() => Text('Count: ${controller.count}')),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: controller.increment,
),
);
}
}
class CounterController extends GetxController{
var count = 0.obs;
increment() => count++;
}
可以将路由、状态管理器和依赖管理器完全集成。 当一个路由从Stack中移除时,所有与它相关的控制器、变量和对象的实例都会从内存中移除。
1)创建一个类并实现Binding,重写 "dependencies"方法,然后插入你要在该路由上使用的所有类。
class HomeBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut(() => HomeController());
Get.put(()=> Api());
}
}
class DetailsBinding implements Bindings {
@override
void dependencies() {
Get.lazyPut(() => DetailsController());
}
}
2)getPages配置 Binding 来建立路由管理器、依赖关系和状态之间的连接。
getPages: [
GetPage(
name: '/',
page: () => HomeView(),
binding: HomeBinding(),
),
GetPage(
name: '/details',
page: () => DetailsView(),
binding: DetailsBinding(),
),
];
通过Bindings可以使用Get的内存管理机制:
Get.to()
/ Get.toNamed()
)Get.put()
或 Binding
类自动初始化控制器实例。Get.back()
)onClose()
方法,并释放其内存。GetX 会自动管理 GetXController 的生命周期。当这个依赖项被创建时,GetX会调用它的 onInit() 和 onReady()方法;当这个依赖项被删除时,GetX 会调用它的 onClose() 方法。
class DemoController extends GetxController {
@override
void onInit() {} // 初始化操作(如加载数据、监听流)
@override
void onReady() {} // 此时 Widget 已渲染完成,适合执行需要依赖 UI 的逻辑(如弹窗、动画)
@override
void onClose() {} // 控制器被销毁时调用,用于释放资源(如关闭流、取消订阅)
}
背景:为了减少首次进入Flutter页面的延迟,通常采用预加载Flutter引擎的策略。当原生应用启动时,预先初始化Flutter引擎,这样当用户跳转到Flutter页面时,引擎已经就绪,页面加载更快。预加载引擎时,引擎会启动Dart虚拟机,执行默认的Dart入口代码。如果入口代码中已经绑定了某个Controller,比如使用GetX的依赖注入,那么引擎初始化时就会创建这些Controller实例。
跳转second页面
-> 执行 Get.toNamed('/second');
-> 执行 SecondController onInit()
-> 执行 SecondController onReady()
关闭页面
-> 执行 Get.back();
-> 执行 SecondController onClose()
App启动
-> 执行 HomeController onInit()
-> 执行 HomeController onReady()
由原生进入Flutter页面
-> 执行 FlutterActivity onCreate()
-> ...
由Flutter页面返回到原生
-> 执行 FlutterActivity onDestroy()
影响:由Flutter页面返回到原生时不会触发控制器的 onClose(),导致状态残留。
AppLifecycleListener 监听“原生到Flutter”、“Flutter到原生”两种状态:“原生到Flutter”时刷新UI;Flutter到原生”时进行状态重置。
late final AppLifecycleListener _listener;
var isFirstEnter = true;
_listener = AppLifecycleListener(
onDetach: _onDetach, //App可能还存有Flutter Engine,但视图并不存在
onResume: _onResume, //App具有输入焦点且可见的正在运行的状态
onRestart: _onRestart,//后台到前台
onPause: _onPause, //前台到后台
);
void _onResume(){
if (isFirstEnter) {
_initState(); //UI刷新
isFirstEnter = false;
}
};
void _onDetach(){
_resetState(); //状态重置
isFirstEnter = true;
};
onDetach
导致状态提前重置。使用MethodChannel监听原生事件,当FlutterActivity关闭(onDestroy)时,重置状态;FlutterActivity创建(onCreate)时,执行UI刷新。
// Flutter 端代码
class MainController extends GetxController {
final MethodChannel _channel = MethodChannel('native_channel');
@override
void onInit() {
_channel.setMethodCallHandler((call) async {
if (call.method == 'onNativeDestroy') {
// 重置控制器状态
_resetState();
} else if (call.method == 'onNativeCreate') {
_initState();
}
});
}
}
getx/README.zh-cn.md at master · jonataslaw/getx · GitHub
getx/documentation/zh_CN/state_management.md at master · jonataslaw/getx · GitHub
getx/documentation/zh_CN/route_management.md at master · jonataslaw/getx · GitHub
getx/documentation/zh_CN/dependency_management.md at master · jonataslaw/getx · GitHub
https://zhuanlan.zhihu.com/p/651402152