引入案例
这里由两个
GetBuilder组成。最外层是
init: CounterController()但是内层使用了
init: controller。那么这个
controller是如何传递到内部的呢。
import 'package:flutter/material.dart';
import 'package:get/get.dart';
/// 控制器
class CounterController extends GetxController {
int count = 0;
void increment() {
count++;
update(['counter']); // 只刷新 counter
}
void reset() {
count = 0;
update(['counter']); // 只刷新 counter
}
}
/// 页面,继承 GetView
class CounterPage extends GetView<CounterController> {
const CounterPage({super.key});
/// 数字展示
Widget _buildCounter() {
return GetBuilder<CounterController>(
id: "counter",
init: controller, // 这里的 controller 就是 Get.find<CounterController>()
builder: (c) =>
Text("计数:${c.count}", style: const TextStyle(fontSize: 24)),
);
}
/// 按钮
Widget _buildButtons() {
return GetBuilder<CounterController>(
id: "buttons",
init: controller,
builder: (c) => Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(onPressed: c.increment, child: const Text("加一")),
const SizedBox(width: 20),
ElevatedButton(onPressed: c.reset, child: const Text("重置")),
],
),
);
}
/// 主体
Widget _buildView() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [_buildCounter(), const SizedBox(height: 20), _buildButtons()],
);
}
@override
Widget build(BuildContext context) {
return GetBuilder<CounterController>(
id: "root",
init: CounterController(), // 外层 init
builder: (_) {
return Scaffold(
appBar: AppBar(title: const Text("嵌套 GetBuilder Demo")),
body: Center(child: _buildView()),
);
},
);
}
}
/// 入口
void main() {
runApp(const GetMaterialApp(home: CounterPage()));
}
init默认注册到容器中
源码
以下是GetBuilder的源码,GetX的源码也类似。都证明:init默认自动注册到全局依赖容器
class GetBuilder<T extends GetxController> extends StatefulWidget {
final GetControllerBuilder<T> builder;
final bool global;
final Object? id;
final String? tag;
final bool autoRemove;
final bool assignId;
final Object Function(T value)? filter;
final void Function(GetBuilderState<T> state)? initState,
dispose,
didChangeDependencies;
final void Function(GetBuilder oldWidget, GetBuilderState<T> state)?
didUpdateWidget;
final T? init;
const GetBuilder({
Key? key,
this.init,
this.global = true,
required this.builder,
this.autoRemove = true,
this.assignId = false,
this.initState,
this.filter,
this.tag,
this.dispose,
this.id,
this.didChangeDependencies,
this.didUpdateWidget,
}) : super(key: key);
@override
GetBuilderState<T> createState() => GetBuilderState<T>();
}
class GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
with GetStateUpdaterMixin {
T? controller;
bool? _isCreator = false;
VoidCallback? _remove;
Object? _filter;
@override
void initState() {
// 调用父类的 initState
super.initState();
// 如果用户在 GetBuilder 里传了 initState 回调,这里会执行
widget.initState?.call(this);
// 判断:这个类型 T 的控制器(可能带 tag)是否已经在 GetX 容器里注册过
var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
// 分两种情况:global = true(默认,全局注册) 或 global = false(局部实例)
if (widget.global) {
if (isRegistered) {
// 已经注册过
if (GetInstance().isPrepared<T>(tag: widget.tag)) {
// 如果是“预注册”状态(lazyPut 的情况),标记 _isCreator = true
_isCreator = true;
} else {
// 如果是普通的已注册实例,标记 _isCreator = false
_isCreator = false;
}
// 从全局容器里拿这个 controller
controller = GetInstance().find<T>(tag: widget.tag);
} else {
// 如果没有注册过,就用 init 传进来的实例
controller = widget.init;
_isCreator = true;
// 并且把这个 controller 注册到全局依赖容器(相当于 Get.put)
GetInstance().put<T>(controller!, tag: widget.tag);
}
} else {
// global = false:完全局部模式,不注册到全局容器
controller = widget.init;
_isCreator = true;
// 手动调用控制器的 onStart 生命周期
controller?.onStart();
}
// 如果用户传了 filter(控制何时刷新 UI),在这里初始化
if (widget.filter != null) {
_filter = widget.filter!(controller!);
}
// 订阅 controller 的更新通知,用来触发 builder 重建
_subscribeToController();
}
widget.global
const GetBuilder({
Key? key,
this.init,
this.global = true, // 👈 默认值是 true
required this.builder,
...
}) : super(key: key);
在 GetBuilder 的构造函数里,默认情况下,global = true
global = true(默认)时,控制器会放进全局依赖容器,页面之间可共享
if (widget.global) {
if (isRegistered) {
controller = GetInstance().find<T>();
} else {
controller = widget.init;
GetInstance().put<T>(controller!); // 👈 自动注册到依赖容器
}
}
- 如果控制器已经在全局容器注册过 →
find()拿到同一个实例 - 如果没注册过 →
put(init)注册到容器
global = false时,控制器是局部的,出这个 widget 就没了
else {
controller = widget.init;
controller?.onStart();
}
- 完全不会往依赖容器注册
- 只是简单地把你传的
init控制器赋值给controller - 生命周期只跟这个
GetBuilder绑定
GetInstance()
GetInstance()是 GetX 的依赖管理容器(本质上是 Get 的底层实现),里面维护了一张 全局的 Map,存储所有 put 进去的实例。
Map<Type, dynamic> _factory = {};
isRegistered<T>():用来判断某个类型 T 的依赖实例有没有被注册过。
GetInstance().isRegistered<T>(tag: widget.tag);
// 等价于
Get.isRegistered<T>(tag: tag);
// 检查某个类型的依赖(可带 tag)是否已经在 GetX 容器里存在。
一个错误
import 'package:flutter/material.dart';
import 'package:get/get.dart';
/// 控制器
class CounterController extends GetxController {
int count = 0;
void increment() {
count++;
update(); // 通知 GetBuilder 刷新
}
void reset() {
count = 0;
update(['counter']); // 只刷新 id 为 counter 的 GetBuilder
}
}
/// 页面
class CounterPage extends GetView<CounterController> {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("GetBuilder + GetView Demo")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
/// 用 GetBuilder 监听
GetBuilder<CounterController>(
id: "counter",
init: CounterController(), // 这里注册全局
builder: (controller) => Text(
"计数:${controller.count}",
style: const TextStyle(fontSize: 24),
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: controller.increment, // 这里会报错
child: const Text("加一"),
),
ElevatedButton(
onPressed: controller.reset,
child: const Text("重置"),
),
],
),
),
);
}
}
上面这个案例报了一个这个错误:
"CounterController" not found. You need to call
"Get.put(CounterController())" or
"Get.lazyPut(()=>CounterController())"
为什么会报错:
GetBuilder的init→ 会自动Get.put(init),把这个CounterController注册到全局容器但是!这个注册动作发生在
GetBuilder的initState()而你在
build()里调用了controller.increment,这时GetBuilder还没执行 initState,所以容器里还没有CounterController而
GetView的controller是Get.find()。结果:
Get.find<CounterController>()找不到实例 → 报错。