Flutter GetX 分析

GetX 是Flutter 中比较早的一个三方库,它包括的功能也很丰富。GetX 主要由响应式状态管理、依赖注入和路由封装组成。https://pub.dev/packages/get

响应式状态管理

1. GetBuilder

我们先介绍第一种状态管理GetBuilder,我们先看一下GetBuilder 如何使用

 GetBuilder<CounterController>(builder: (c) => Text('${c.counter.value}'));

上面的代码是GetBuilder的最基本的用法,我们从源码层面逐步分析一下counter.value动态变化时,CounterController 里手动调用update时更新UI

import 'package:flutter/material.dart';
import '../../../get_instance/src/get_instance.dart';
import '../../../instance_manager.dart';
import '../../get_state_manager.dart';
import 'list_notifier.dart';

/// Complies with `GetStateUpdater`
///
/// This mixin's function represents a `GetStateUpdater`, and might be used
/// by `GetBuilder()`, `SimpleBuilder()` (or similar) to comply
/// with [GetStateUpdate] signature. REPLACING the [StateSetter].
/// Avoids the potential (but extremely unlikely) issue of having
/// the Widget in a dispose() state, and abstracts the
/// API from the ugly fn((){}).
mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> {
  // To avoid the creation of an anonym function to be GC later.
  // ignore: prefer_function_declarations_over_variables

  /// Experimental method to replace setState((){});
  /// Used with GetStateUpdate.
  void getUpdate() {
    if (mounted) setState(() {});
  }
}

typedef GetControllerBuilder<T extends DisposableInterface> = Widget Function(
    T controller);

// class _InheritedGetxController<T extends GetxController>
//     extends InheritedWidget {
//   final T model;
//   final int version;

//   _InheritedGetxController({
//     Key key,
//     @required Widget child,
//     @required this.model,
//   })  : version = model.notifierVersion,
//         super(key: key, child: child);

//   @override
//   bool updateShouldNotify(_InheritedGetxController<T> oldWidget) =>
//       (oldWidget.version != version);
// }

// extension WatchEtx on GetxController {
//   T watch<T extends GetxController>() {
//     final instance = Get.find<T>();
//     _GetBuilderState._currentState.watch(instance.update);
//     return instance;
//   }
// }

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);

  // static T of<T extends GetxController>(
  //   BuildContext context, {
  //   bool rebuild = false,
  // }) {
  //   var widget = rebuild
  //       ? context
  //       .dependOnInheritedWidgetOfExactType<_InheritedGetxController<T>>()
  //       : context
  //           .getElementForInheritedWidgetOfExactType<
  //               _InheritedGetxController<T>>()
  //           ?.widget;

  //   if (widget == null) {
  //     throw 'Error: Could not find the correct dependency.';
  //   } else {
  //     return (widget as _InheritedGetxController<T>).model;
  //   }
  // }

  @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() {
    // _GetBuilderState._currentState = this;
    super.initState();
    widget.initState?.call(this);

    var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);

    if (widget.global) {
      if (isRegistered) {
        if (GetInstance().isPrepared<T>(tag: widget.tag)) {
          _isCreator = true;
        } else {
          _isCreator = false;
        }
        controller = GetInstance().find<T>(tag: widget.tag);
      } else {
        controller = widget.init;
        _isCreator = true;
        GetInstance().put<T>(controller!, tag: widget.tag);
      }
    } else {
      controller = widget.init;
      _isCreator = true;
      controller?.onStart();
    }

    if (widget.filter != null) {
      _filter = widget.filter!(controller!);
    }

    _subscribeToController();
  }

  /// Register to listen Controller's events.
  /// It gets a reference to the remove() callback, to delete the
  /// setState "link" from the Controller.
  void _subscribeToController() {
    _remove?.call();
    _remove = (widget.id == null)
        ? controller?.addListener(
            _filter != null ? _filterUpdate : getUpdate,
          )
        : controller?.addListenerId(
            widget.id,
            _filter != null ? _filterUpdate : getUpdate,
          );
  }

  void _filterUpdate() {
    var newFilter = widget.filter!(controller!);
    if (newFilter != _filter) {
      _filter = newFilter;
      getUpdate();
    }
  }

  @override
  void dispose() {
    super.dispose();
    widget.dispose?.call(this);
    if (_isCreator! || widget.assignId) {
      if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) {
        GetInstance().delete<T>(tag: widget.tag);
      }
    }

    _remove?.call();

    controller = null;
    _isCreator = null;
    _remove = null;
    _filter = null;
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    widget.didChangeDependencies?.call(this);
  }

  @override
  void didUpdateWidget(GetBuilder oldWidget) {
    super.didUpdateWidget(oldWidget as GetBuilder<T>);
    // to avoid conflicts when modifying a "grouped" id list.
    if (oldWidget.id != widget.id) {
      _subscribeToController();
    }
    widget.didUpdateWidget?.call(oldWidget, this);
  }

  @override
  Widget build(BuildContext context) {
    // return _InheritedGetxController<T>(
    //   model: controller,
    //   child: widget.builder(controller),
    // );
    return widget.builder(controller!);
  }
}

我们通过这个源码看到GetBuilder是在要更新的局部UI外层包一层StatefulWidget,局部动态刷新的UI传给builder这个参数,核心方法处理都在GetBuilderState里我们先看一下initState 里都做了什么
泛型T 接受的是继承了GetxController的Controller,示例代码中指的就是CounterController
widget.initState?.call(this);
可选执行用户传入的初始化回调(没传就跳过)
var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
做的是一件很简单的事:查 GetX 依赖注入容器里(Map<String, _InstanceBuilderFactory> ),这个「类型 + tag」生成的key对应的 Controller 有没有登记过。它不会创建实例,也不会调用 find,只是一次 Map 查 key
之前controller 被Get.put 进入到全局的Map 里了isRegistered就是true,否则就是false

后面的if else 里面的代码就不一一解释了,整体的操作就是获取对应的controller 实例复制给 GetBuilderState 里的controller 属性
接下来我们看 _subscribeToController() 方法
_subscribeToController() 的作用是:
1.先退订(_remove?.call())
2.再订阅:把本 GetBuilder 的 getUpdate(或 _filterUpdate)挂到 Controller 上
Disposer addListener(GetStateUpdate listener) {
assert(_debugAssertNotDisposed());
_updaters!.add(listener);
return () => _updaters!.remove(listener);
}
listener 这个监听方法添加到List<GetStateUpdate?>? _updaters里,
我们着重看一下添加到_updaters里的listener是个什么?
_remove = (widget.id == null)
? controller?.addListener(
_filter != null ? _filterUpdate : getUpdate,
)
: controller?.addListenerId(
widget.id,
_filter != null ? _filterUpdate : getUpdate,
);

_filterUpdate或getUpdate, 在跟分别进去看一下这两个
void _filterUpdate() {
var newFilter = widget.filter!(controller!);
if (newFilter != _filter) {
_filter = newFilter;
getUpdate();
}
}

mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> {
// To avoid the creation of an anonym function to be GC later.
// ignore: prefer_function_declarations_over_variables

/// Experimental method to replace setState((){});
/// Used with GetStateUpdate.
void getUpdate() {
if (mounted) setState(() {});
}
}

我们看代码可以看到最核心的更新UI 的方法getUpdate 是GetStateUpdater的Mixin方法,里面刷新UI 的方式还是通过setState 来实现
3.按 id 决定挂全局还是分组列表
4.把新的取消函数存进 _remove,供下次重订阅或 dispose 使用
这个方法是 GetBuilder「能响应 update() 自动重建」的核心机制;没有这一步,update() 只会改 Controller 数据,UI 不会变。

我们在看一下update()方法里是如相应让UI刷新UI的,我们通过看代码update 里的refresh 的逻辑也很简单就是一个for 循环,遍历_updaters诸葛执行里面的listener,也是setState 方法来去更新UI


void update([List<Object>? ids, bool condition = true]) {
    if (!condition) {
      return;
    }
    if (ids == null) {
      refresh();
    } else {
      for (final id in ids) {
        refreshGroup(id);
      }
    }
  }
 下面是refresh 方法的实现
 import 'dart:collection';

import 'package:flutter/widgets.dart';

// This callback remove the listener on addListener function
typedef Disposer = void Function();

// replacing StateSetter, return if the Widget is mounted for extra validation.
// if it brings overhead the extra call,
typedef GetStateUpdate = void Function();

class ListNotifier extends Listenable with ListenableMixin, ListNotifierMixin {}

mixin ListenableMixin implements Listenable {}
mixin ListNotifierMixin on ListenableMixin {
  // int _version = 0;
  // int _microtask = 0;

  // int get notifierVersion => _version;
  // int get notifierMicrotask => _microtask;

  List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[];

  HashMap<Object?, List<GetStateUpdate>>? _updatersGroupIds =
      HashMap<Object?, List<GetStateUpdate>>();

  @protected
  void refresh() {
    assert(_debugAssertNotDisposed());

    /// This debounce the call to update.
    /// It prevent errors and duplicates builds
    // if (_microtask == _version) {
    //   _microtask++;
    //   scheduleMicrotask(() {
    //     _version++;
    //     _microtask = _version;
    _notifyUpdate();
    // });
    // }
  }

  void _notifyUpdate() {
    for (var element in _updaters!) {
      element!();
    }
  }

  void _notifyIdUpdate(Object id) {
    if (_updatersGroupIds!.containsKey(id)) {
      final listGroup = _updatersGroupIds![id]!;
      for (var item in listGroup) {
        item();
      }
    }
  }

  @protected
  void refreshGroup(Object id) {
    assert(_debugAssertNotDisposed());

    // /// This debounce the call to update.
    // /// It prevent errors and duplicates builds
    // if (_microtask == _version) {
    //   _microtask++;
    //   scheduleMicrotask(() {
    //     _version++;
    //     _microtask = _version;
    _notifyIdUpdate(id);
    // });
    // }
  }

  bool _debugAssertNotDisposed() {
    assert(() {
      if (_updaters == null) {
        throw FlutterError('''A $runtimeType was used after being disposed.\n
'Once you have called dispose() on a $runtimeType, it can no longer be used.''');
      }
      return true;
    }());
    return true;
  }

  @protected
  void notifyChildrens() {
    TaskManager.instance.notify(_updaters);
  }

  bool get hasListeners {
    assert(_debugAssertNotDisposed());
    return _updaters!.isNotEmpty;
  }

  int get listeners {
    assert(_debugAssertNotDisposed());
    return _updaters!.length;
  }

  @override
  void removeListener(VoidCallback listener) {
    assert(_debugAssertNotDisposed());
    _updaters!.remove(listener);
  }

  void removeListenerId(Object id, VoidCallback listener) {
    assert(_debugAssertNotDisposed());
    if (_updatersGroupIds!.containsKey(id)) {
      _updatersGroupIds![id]!.remove(listener);
    }
    _updaters!.remove(listener);
  }

  @mustCallSuper
  void dispose() {
    assert(_debugAssertNotDisposed());
    _updaters = null;
    _updatersGroupIds = null;
  }

  @override
  Disposer addListener(GetStateUpdate listener) {
    assert(_debugAssertNotDisposed());
    _updaters!.add(listener);
    return () => _updaters!.remove(listener);
  }

  Disposer addListenerId(Object? key, GetStateUpdate listener) {
    _updatersGroupIds![key] ??= <GetStateUpdate>[];
    _updatersGroupIds![key]!.add(listener);
    return () => _updatersGroupIds![key]!.remove(listener);
  }

  /// To dispose an [id] from future updates(), this ids are registered
  /// by `GetBuilder()` or similar, so is a way to unlink the state change with
  /// the Widget from the Controller.
  void disposeId(Object id) {
    _updatersGroupIds!.remove(id);
  }
}

刚才我们看GetBuilder 里有id 和tag 两根参数,我们看一下这两个参数的作用和区别

// 同一个 tag: 'cart' 实例,两个不同 id 的 UI
GetBuilder<CounterController>(
  tag: 'cart',
  id: 'badge',           // 角标
  builder: (c) => Text('${c.counter.value}'),
);

GetBuilder<CounterController>(
  tag: 'cart',
  id: 'detail',          // 详情文字
  builder: (c) => Text('共 ${c.counter.value} 件商品'),
);

// 只刷新角标,不动详情
Get.find<CounterController>(tag: 'cart').update(['badge']);

tag:先确定操作的是「购物车」还是「收藏夹」哪个实例
id:在这个实例里,再确定刷新「角标」还是「详情」哪块 UI

没有 tag 时,同类型全项目共享一个controller实例;有 tag 时,可以并存多个独立controller实例,各自维护状态、各自响应 update()。
简单的说tag 是controller的tag, Get中存储Controller 的全局map 中可以存储多个同类型的Controller里 CounterController 可以有多个实例,通过tag 区分不同的CounterController 实例分别处理不同的逻辑
id 是GetBuilder 的id区分UI 的标识,多个GetBuilder绑定同一个Controller 时,但是刷新UI 又不能同时刷新,可以通过id 进行区分,单独刷新各自的UI。

一句话总结:GetBuilder 包裹UI,变成StatefulWidget, GetBuilderState 初始化时绑定对应的继承GetxController的Controller。 _subscribeToController (在初始化方法里调用)方法里把getUpdate(内部实现就是setState 方法)更新UI方法添加到controller 中的updaters 数组里,Controller中手动执行update方法时,就是一个for 循环来遍历updaters,逐个执行getUpdate 方法去刷新UI。

2. Obx

Obx 也是GetX中实现状态管理的一种方式我们也从源码层级分析一下它的实现原理

class Obx extends ObxWidget {
  final WidgetCallback builder;

  const Obx(this.builder, {Key? key}) : super(key: key);

  @override
  Widget build() => builder();
}

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import '../../../get_rx/src/rx_types/rx_types.dart';

typedef WidgetCallback = Widget Function();

/// The [ObxWidget] is the base for all GetX reactive widgets
///
/// See also:
/// - [Obx]
/// - [ObxValue]
abstract class ObxWidget extends StatefulWidget {
  const ObxWidget({Key? key}) : super(key: key);

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(ObjectFlagProperty<Function>.has('builder', build));
  }

  @override
  ObxState createState() => ObxState();

  @protected
  Widget build();
}

class ObxState extends State<ObxWidget> {
  final _observer = RxNotifier();
  late StreamSubscription subs;

  @override
  void initState() {
    super.initState();
    subs = _observer.listen(_updateTree, cancelOnError: false);
  }

  void _updateTree(_) {
    if (mounted) {
      setState(() {});
    }
  }

  @override
  void dispose() {
    subs.cancel();
    _observer.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) =>
      RxInterface.notifyChildren(_observer, widget.build);
}

/// The simplest reactive widget in GetX.
///
/// Just pass your Rx variable in the root scope of the callback to have it
/// automatically registered for changes.
///
/// final _name = "GetX".obs;
/// Obx(() => Text( _name.value )),... ;
class Obx extends ObxWidget {
  final WidgetCallback builder;

  const Obx(this.builder, {Key? key}) : super(key: key);

  @override
  Widget build() => builder();
}

/// Similar to Obx, but manages a local state.
/// Pass the initial data in constructor.
/// Useful for simple local states, like toggles, visibility, themes,
/// button states, etc.
///  Sample:
///    ObxValue((data) => Switch(
///      value: data.value,
///      onChanged: (flag) => data.value = flag,
///    ),
///    false.obs,
///   ),
class ObxValue<T extends RxInterface> extends ObxWidget {
  final Widget Function(T) builder;
  final T data;

  const ObxValue(this.builder, this.data, {Key? key}) : super(key: key);

  @override
  Widget build() => builder(data);
}

我们通过看源码Obx 更GetBuilder 完全不同,Obx 继承 ObxWidget, ObxWidget 也是一个 StatefulWidget,核心的逻辑在ObxState 里处理的

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';

import '../../../get_rx/src/rx_types/rx_types.dart';

typedef WidgetCallback = Widget Function();

/// The [ObxWidget] is the base for all GetX reactive widgets
///
/// See also:
/// - [Obx]
/// - [ObxValue]
abstract class ObxWidget extends StatefulWidget {
  const ObxWidget({Key? key}) : super(key: key);

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(ObjectFlagProperty<Function>.has('builder', build));
  }

  @override
  ObxState createState() => ObxState();

  @protected
  Widget build();
}

class ObxState extends State<ObxWidget> {
  final _observer = RxNotifier();
  late StreamSubscription subs;

  @override
  void initState() {
    super.initState();
    subs = _observer.listen(_updateTree, cancelOnError: false);
  }

  void _updateTree(_) {
    if (mounted) {
      setState(() {});
    }
  }

  @override
  void dispose() {
    subs.cancel();
    _observer.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) =>
      RxInterface.notifyChildren(_observer, widget.build);
}

/// The simplest reactive widget in GetX.
///
/// Just pass your Rx variable in the root scope of the callback to have it
/// automatically registered for changes.
///
/// final _name = "GetX".obs;
/// Obx(() => Text( _name.value )),... ;
class Obx extends ObxWidget {
  final WidgetCallback builder;

  const Obx(this.builder, {Key? key}) : super(key: key);

  @override
  Widget build() => builder();
}

class ObxValue<T extends RxInterface> extends ObxWidget {
  final Widget Function(T) builder;
  final T data;

  const ObxValue(this.builder, this.data, {Key? key}) : super(key: key);

  @override
  Widget build() => builder(data);
}

我们看ObxState里代码很简单,initState 里给_observer 添加更新UI 的监听方法,监听方法_updateTree 也很简单,实际还是调用的setState方法去刷新UI, 怎么实现监听的value 值变化后就响应UI的update,这个是关键的步骤。
首先我们先看value 是如何跟ObxWidget 做的绑定
在initiate阶段UI 还没和value 绑定,只是 Obx 先监听 自己的 _observer.subject,任何 Rx 变化要能刷新 UI,必须先经过 _observer 转发,绑定的逻辑是发生在第一次 build时

 Widget build(BuildContext context) =>
      RxInterface.notifyChildren(_observer, widget.build);

abstract class RxInterface<T> {
  static RxInterface? proxy;

  bool get canUpdate;

  /// Adds a listener to stream
  void addListener(GetStream<T> rxGetx);

  /// Close the Rx Variable
  void close();

  /// Calls `callback` with current value, when the value changes.
  StreamSubscription<T> listen(void Function(T event) onData,
      {Function? onError, void Function()? onDone, bool? cancelOnError});

  /// Avoids an unsafe usage of the `proxy`
  static T notifyChildren<T>(RxNotifier observer, ValueGetter<T> builder) {
    final oldObserver = RxInterface.proxy;
    RxInterface.proxy = observer;
    final result = builder();
    if (!observer.canUpdate) {
      RxInterface.proxy = oldObserver;
      throw """
      [Get] the improper use of a GetX has been detected. 
      You should only use GetX or Obx for the specific widget that will be updated.
      If you are seeing this error, you probably did not insert any observable variables into GetX/Obx 
      or insert them outside the scope that GetX considers suitable for an update 
      (example: GetX => HeavyWidget => variableObservable).
      If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
      """;
    }
    RxInterface.proxy = oldObserver;
    return result;
  }
}

我们看这个build 方法里吧_observer 和 widget.build 传到RxInterface.notifyChildren方法主要作用是在UI重新刷新执行前设置好proxy为observer(ObxState 里的RxNotifier实例对象,value值变化时update UI 的监听操作),让 getter 里的 addListener 生效,getter 方法里的proxy 此时已经是我们创建的observer,给observer添加监听方法,我们看下面的addListener 方法里实际是一个GetStream对象,在ObxState 初始化方法里的_observer.listen(_updateTree, cancelOnError: false); 已经把_updateTree 更新UI 的监听方法传给了 GetStream 对象,当调用监听的数据执行set 方法时,会执行GetStream的add方法触发stream 的listen 监听方法执行_updateTree更新UI的状态

class RxNotifier<T> = RxInterface<T> with NotifyManager<T>;

mixin NotifyManager<T> {
  GetStream<T> subject = GetStream<T>();
  final _subscriptions = <GetStream, List<StreamSubscription>>{};

  bool get canUpdate => _subscriptions.isNotEmpty;

  /// This is an internal method.
  /// Subscribe to changes on the inner stream.
  void addListener(GetStream<T> rxGetx) {
    if (!_subscriptions.containsKey(rxGetx)) {
      final subs = rxGetx.listen((data) {
        if (!subject.isClosed) subject.add(data);
      });
      final listSubscriptions =
          _subscriptions[rxGetx] ??= <StreamSubscription>[];
      listSubscriptions.add(subs);
    }
  }

  StreamSubscription<T> listen(
    void Function(T) onData, {
    Function? onError,
    void Function()? onDone,
    bool? cancelOnError,
  }) =>
      subject.listen(
        onData,
        onError: onError,
        onDone: onDone,
        cancelOnError: cancelOnError ?? false,
      );

  /// Closes the subscriptions for this Rx, releasing the resources.
  void close() {
    _subscriptions.forEach((getStream, subscriptions) {
      for (final subscription in subscriptions) {
        subscription.cancel();
      }
    });

    _subscriptions.clear();
    subject.close();
  }
}

总结:
阶段 1:挂载 —— initState
class ObxState extends State<ObxWidget> {
final _observer = RxNotifier();
...
void initState() {
subs = _observer.listen(_updateTree, cancelOnError: false);
}
阶段 2:首次 build —— 依赖收集 + UI 渲染

rx_obx_widget.dart
Lines 54-56
Widget build(BuildContext context) =>
RxInterface.notifyChildren(_observer, widget.build);
notifyChildren 三步:

rx_interface.dart
Lines 23-39
RxInterface.proxy = observer; // ① 设全局 proxy
final result = builder(); // ② 执行你的 builder
if (!observer.canUpdate) throw ...; // ③ 校验至少绑定了一个 Rx
RxInterface.proxy = oldObserver; // ④ 恢复 proxy
return result;
builder() 内部(例如 Text('{name.value} ·{age.value}')):

每次访问 .value 触发 getter:

rx_impl.dart
Lines 108-112
T get value {
RxInterface.proxy?.addListener(subject); // 登记依赖 + 桥接
return _value; // 返回当前值用于渲染
}
addListener 建立桥接:

rx_impl.dart
Lines 155-163
void addListener(GetStream<T> rxGetx) {
if (!_subscriptions.containsKey(rxGetx)) {
final subs = rxGetx.listen((data) {
subject.add(data); // Rx 变 → 转发到 _observer.subject
});
_subscriptions[rxGetx] = [subs];
}
}
首次 build 结束后的结构:

_observer._subscriptions = {
name.subject → listen → _observer.subject,
age.subject → listen → _observer.subject,
}
_observer.subject → listen → _updateTree → setState
同一步完成两件事:绑定依赖 + 用当前 value 画出 UI。

阶段 3:value 变化 —— 通知 → 重建
用户改值,例如 counter.value++:

rx_impl.dart
Lines 98-105
set value(T val) {
_value = val;
subject.add(_value); // ① Rx 的 Stream 发事件
}
事件链:

counter.subject.add(新值)
↓ 桥接 listen(阶段 2 建立的)
_observer.subject.add(新值)
↓ initState 里建立的 listen
_updateTree()

setState() // ② 标记 Obx 需要重建

build() → notifyChildren // ③ 重新收集依赖 + 读新 value 渲染
通知靠 GetStream(Stream 模式);UI 重建靠 setState(不是 StreamBuilder)。

阶段 4:销毁 —— dispose

rx_obx_widget.dart
Lines 47-51
void dispose() {
subs.cancel();
_observer.close(); // 取消所有桥接订阅
}
close() 遍历 _subscriptions 全部 cancel,防止泄漏。

三、总流程图


image.png

我们分析了Obx 和GetBuilder 的实现原理,对比一下这两种方式的使用场景

Obx vs GetBuilder:性能差异与场景选择
性能上没有绝对的「谁更快」,差别主要在 重建范围、触发频率、每次 rebuild 的开销。
单次 rebuild 谁更轻?
GetBuilder 略轻(理论上)

get_state.dart
Lines 206-212
Widget build(BuildContext context) {
return widget.builder(controller!); // 直接构建
}

rx_obx_widget.dart
Lines 54-56
Widget build(BuildContext context) =>
RxInterface.notifyChildren(_observer, widget.build); // 多一层 proxy 机制
Obx 每次 build 都要:设 proxy → 跑 builder → 校验 canUpdate → 恢复 proxy。
GetBuilder 只是调 builder,单次 rebuild 开销略小。
但这点差异在普通 UI 里通常 可忽略;真正影响性能的是 重建范围和频率


image.png

image.png

image.png

依赖注入

从 GetX 源码里顺着 GetInstance、put/find 和生命周期管理往下读,梳理依赖注入的实现。

  1. 整体架构
    Get.put / lazyPut / create

    GetInstance._insert() → 写入 _singl Map

    Get.find / GetBuilder / GetX

    GetInstance.find()

    _initDependencies() → _startController() → onStart() → onInit()

    Get.delete / 路由销毁

    onDelete() → onClose() → 从 Map 移除(或 fenix 保留工厂)
    核心容器

get_instance.dart
Lines 23-34
class GetInstance {
factory GetInstance() => getInstance ??= const GetInstance.();
...
static final Map<String, _InstanceBuilderFactory> _singl = {};
GetInstance:DI 容器(单例)
_singl:全局注册表,key → 工厂/实例
Get.put/find:通过 extension 转发到 GetInstance

extension_instance.dart
Lines 85-89
S put<S>(S dependency, {String? tag, bool permanent = false, ...}) =>
GetInstance().put<S>(dependency, tag: tag, permanent: permanent);
S find<S>({String? tag}) => GetInstance().find<S>(tag: tag);

  1. Key 如何生成(类型 + tag)

get_instance.dart
Lines 312-314
String _getKey(Type type, String? name) {
return name == null ? type.toString() : type.toString() + name;
}
注册方式 key 示例
Get.put(CounterController())
"CounterController"
Get.put(Ctrl(), tag: 'cart')
"CounterControllercart"
同类型多实例靠 tag 拼 key 区分。

  1. 注册:_InstanceBuilderFactory + _insert
    所有注册最终进 _insert:

get_instance.dart
Lines 157-188
void _insert<S>({..., required InstanceBuilderCallback<S> builder, bool fenix = false}) {
final key = _getKey(S, name);
if (!_singl.containsKey(key)) {
_singl[key] = _InstanceBuilderFactory<S>(...);
}
}
工厂对象字段:

get_instance.dart
Lines 492-519
class _InstanceBuilderFactory<S> {
bool? isSingleton; // 单例 or 每次新建
bool fenix; // 删除后是否保留工厂以便重建
S? dependency; // 已创建的实例(单例缓存)
InstanceBuilderCallback<S> builderFunc; // 创建函数
bool permanent = false; // 是否永久驻内存
bool isInit = false; // 生命周期是否已启动
...
}
真正创建实例:

get_instance.dart
Lines 540-549
S getDependency() {
if (isSingleton!) {
if (dependency == null) {
dependency = builderFunc(); // 懒创建:第一次才 new
}
return dependency!;
} else {
return builderFunc(); // 非单例:每次都 new
}
}

  1. 三种注册 API 的区别
    ① Get.put — 立即注册(实例可懒创建)

get_instance.dart
Lines 75-87
S put<S>(S dependency, {String? tag, bool permanent = false, ...}) {
_insert(isSingleton: true, name: tag, builder: () => dependency);
return find<S>(tag: tag); // 立刻 find → 触发初始化
}
传入已有对象或工厂
put 后会 find,触发 onInit
你项目里的 Get.put(CounterController()) 走这条路径
② Get.lazyPut — 只登记工厂,首次 find 才创建

get_instance.dart
Lines 112-124
void lazyPut<S>(InstanceBuilderCallback<S> builder, {String? tag, bool? fenix, ...}) {
_insert(isSingleton: true, name: tag, builder: builder,
fenix: fenix ?? Get.smartManagement == SmartManagement.keepFactory);
}
Map 里有 key,但 dependency == null
isPrepared == true(已注册未初始化)
第一次 find 才 builderFunc() 创建
③ Get.create — 每次 find 新建实例

get_instance.dart
Lines 143-153
void create<S>(InstanceBuilderCallback<S> builder, {String? tag, bool permanent = true}) {
_insert(isSingleton: false, name: tag, builder: builder, permanent: permanent);
}
isSingleton: false → getDependency() 每次都 builderFunc(),find 两次得到两个对象。

  1. 查找:find 完整流程

get_instance.dart
Lines 282-307
S find<S>({String? tag}) {
final key = _getKey(S, tag);
if (isRegistered<S>(tag: tag)) {
final dep = _singl[key];
final i = _initDependencies<S>(name: tag); // 启动生命周期
return i ?? dep.getDependency() as S; // 返回实例
} else {
throw '"$S" not found...';
}
}
_initDependencies — 只初始化一次

get_instance.dart
Lines 200-213
S? _initDependencies<S>({String? name}) {
if (!isInit) {
i = _startController<S>(tag: name);
if (isSingleton) {
_singl[key]!.isInit = true;
RouterReportManager.reportDependencyLinkedToRoute(key); // 绑定当前路由
}
}
return i;
}
_startController — 触发生命周期

get_instance.dart
Lines 250-264
S _startController<S>({String? tag}) {
final i = _singl[key]!.getDependency() as S;
if (i is GetLifeCycleBase) {
i.onStart(); // → onInit() → 下一帧 onReady()
}
return i;
}

  1. 生命周期源码链

lifecycle.dart
Lines 82-86
void $configureLifeCycle() {
onStart._callback = _onStart; // onStart() → onInit()
onDelete._callback = _onDelete; // onDelete() → onClose()
}

lifecycle.dart
Lines 64-67
void _onStart() {
if (_initialized) return;
onInit();
_initialized = true;
}
GetxController 继承 DisposableInterface:

rx_disposable.dart
Lines 17-21
void onInit() {
super.onInit();
Get.engine.addPostFrameCallback((_) => onReady()); // 下一帧 onReady
}
完整顺序:

find / put
→ onStart()
→ onInit()
→ (下一帧) onReady()
delete / 路由销毁
→ onDelete()
→ onClose()

  1. 销毁:delete 与 fenix

get_instance.dart
Lines 348-404
bool delete<S>({String? tag, String? key, bool force = false}) {
if (builder.permanent && !force) return false; // permanent 不删
if (i is GetLifeCycleBase) i.onDelete(); // onClose
if (builder.fenix) {
builder.dependency = null;
builder.isInit = false; // 保留工厂,下次 find 重建
return true;
} else {
_singl.remove(newKey); // 彻底移除
return true;
}
}
模式 行为
普通 delete
从 Map 移除,实例销毁
fenix: true
清实例,保留 builderFunc,下次 find 重建
permanent: true
默认 delete 删不掉(需 force: true)

  1. SmartManagement:路由级自动回收

smart_management.dart
Lines 18-22
enum SmartManagement {
full, // 默认:路由销毁时删非 permanent 依赖
onlyBuilder, // 仅 GetBuilder/lazyPut 创建的会回收
keepFactory, // 同 full,但保留工厂(类似 fenix)
}
依赖与路由绑定
find 初始化时:

get_instance.dart
Lines 208-209
RouterReportManager.reportDependencyLinkedToRoute(_getKey(S, name));

router_report.dart
Lines 31-37
static void reportDependencyLinkedToRoute(String depedencyKey) {
_routesKey[_current]!.add(depedencyKey); // 记录:此路由用了哪些 key
}
路由 pop 时自动 delete

router_report.dart
Lines 51-57
static void reportRouteDispose(Route disposed) {
if (Get.smartManagement != SmartManagement.onlyBuilder) {
_removeDependencyByRoute(disposed); // 逐个 Get.delete(key)
}
}
离开页面 → 该页注册的 Controller 自动 delete → onClose(),无需手动释放。

  1. Bindings:路由级批量注册

bindings_interface.dart
Lines 9-11
abstract class Bindings {
void dependencies();
}
GetPage(
name: '/home',
page: () => HomePage(),
binding: BindingsBuilder(() {
Get.lazyPut(() => HomeController());
}),
)
打开路由 → 调 binding.dependencies() → 执行 lazyPut/put → 写入 _singl。
关闭路由 → SmartManagement → 自动 delete。

  1. 与 GetBuilder 的集成(DI + UI)

get_state.dart
Lines 121-134
var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
if (isRegistered) {
controller = GetInstance().find<T>(tag: widget.tag); // 复用
} else {
controller = widget.init;
GetInstance().put<T>(controller!, tag: widget.tag); // 注册
}
GetBuilder 是 DI 的 消费者:global: true 时自动 find/put,dispose 时 _isCreator 为 true 则 Get.delete。

  1. 完整流程图(以你的 Counter 为例)
    final controller = Get.put(CounterController());
    Get.put(CounterController())

    ├─ _insert(key: "CounterController", builder: () => instance, isSingleton: true)
    │ _singl["CounterController"] = _InstanceBuilderFactory(dependency: instance)

    └─ find<CounterController>()

    ├─ _initDependencies (isInit: false)
    │ ├─ getDependency() → 返回 CounterController
    │ ├─ onStart() → onInit() → 注册 onReady 下一帧
    │ ├─ isInit = true
    │ └─ reportDependencyLinkedToRoute("CounterController")

    └─ 返回 controller 实例
    页面销毁(SmartManagement.full):

Route.pop
→ reportRouteDispose
→ delete(key: "CounterController")
→ onDelete() → onClose()
→ _singl.remove("CounterController")

  1. API 对照表


    image.png
  2. 设计要点小结
    Service Locator:全局 _singl Map,按类型+tag 查找,不是构造函数注入。
    懒创建:dependency == null 时 builderFunc() 才执行。
    生命周期内建:onInit/onReady/onClose 与 find/delete 绑定。
    路由感知:RouterReportManager 把依赖挂到 Route,pop 时自动清理。
    fenix / permanent:控制「删实例是否保留工厂」「是否可被 SmartManagement 删」。
    与 UI 耦合:GetBuilder/GetX 通过 find/put/delete 管理 Controller 存活。
  3. 一句话
    GetX DI = GetInstance._singl 注册表 + _InstanceBuilderFactory 懒/单例创建 + find 触发生命周期 + RouterReportManager 按路由自动 delete。
    Get.put 是注册入口,Get.find 是获取并初始化入口,Get.delete(或路由销毁)是回收入口。

路由管理

GetX 路由是在 Flutter Navigator 之上封装 的:保留 push/pop 栈模型,增加 无 Context 导航、路由表、Middleware、Bindings、DI 生命周期绑定。


image.png

image.png
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容